"""
SL CAT TOPUP CENTER - Public Web Store Application
Fast, Modern Flask Application with Dynamic LankaQR and Automated HTG Fulfillment.
"""

import os
import sys
import time
import json
import urllib.parse
import uuid
import logging
import requests
import hashlib
import threading
from datetime import datetime
from typing import Dict, Any, List, Optional, Tuple

logger = logging.getLogger("app")

if sys.platform == "win32":
    try:
        sys.stdout.reconfigure(encoding="utf-8")
        sys.stderr.reconfigure(encoding="utf-8")
    except Exception:
        pass

from flask import Flask, render_template, request, jsonify, redirect, url_for, session, Response, g
from werkzeug.utils import secure_filename

from config import (
    SERVER_HOST,
    SERVER_PORT,
    UPLOAD_FOLDER,
    ADMIN_PIN,
    ADMIN_FF_ID,
    CLIENT_PRICES,
    BANK_ACCOUNTS,
    get_product_price,
)
from lanka_qr import get_dynamic_lankaqr, generate_qr_base64
from database import (
    init_db,
    get_connection,
    create_order,
    get_order,
    update_order_payment,
    mark_order_processing,
    mark_order_completed,
    mark_order_failed,
    refund_failed_order,
    auto_reject_stale_orders,
    generate_unique_order_amount,
    find_pending_order_by_amount,
    find_matching_notification,
    mark_notification_matched,
    record_bank_notification,
    get_all_orders,
    get_admin_stats,
    record_site_visitor,
    get_visitor_stats,
    get_setting,
    set_setting,
    reject_order,
    register_user,
    authenticate_user,
    get_user_by_id,
    update_user_profile,
    update_user_saved_uid,
    reset_user_pin_verified,
    admin_reset_user_pin,
    set_user_email_otp,
    verify_user_email_otp,
    get_user_orders,
    get_user_wallet_balance,
    credit_wallet,
    debit_wallet,
    get_wallet_transactions,
    get_all_users_with_wallets,
    admin_adjust_wallet,
    can_user_spin,
    record_spin,
    get_monthly_leaderboard,
    get_recent_public_purchases,
    validate_coupon,
    record_coupon_usage,
    check_duplicate_slip,
    compute_image_dhash,
    is_device_or_ip_banned,
    ban_device,
    unban_device,
    get_banned_devices,
    ban_user,
    unban_user,
    save_chat_rating,
    get_chat_rating_stats,
    get_all_coupons,
    add_coupon,
    toggle_coupon_status,
    delete_coupon,
    create_admin_ticket,
    get_all_admin_tickets,
    get_admin_ticket,
    reply_admin_ticket,
    customer_reply_admin_ticket,
    get_open_tickets_count,
    record_mystery_box_open,
    get_recent_mystery_box_winners,
    get_mystery_box_stats,
    get_user_daily_mystery_luck,
    record_user_daily_mystery_luck,
)
from htg_engine import (
    check_player_uid,
    get_store_products,
    check_htg_balance,
    execute_htg_topup,
    create_visa_payment_link,
    check_visa_transactions,
    sync_missing_visa_recharge,
    PRODUCT_CATALOG,
    get_all_htg_accounts_status,
    set_active_account,
    set_auto_failover,
    update_account_cookies,
    refresh_all_accounts_balance,
)
from htg_stock_manager import (
    get_all_products_live_stock,
    validate_order_stock,
    get_stock_configuration,
    save_stock_configuration,
    force_sync_htg_and_refresh_stock,
    invalidate_stock_cache,
    get_htg_wholesale_cost,
)
from manu_engine import (
    verify_player_uid_manu,
    create_manu_order,
    check_manu_order_status,
    get_manu_orders_by_email,
    generate_manu_whatsapp_link,
    MANU_PACKAGES_MAP,
)

app = Flask(__name__)
application = app  # Support both 'app' and 'application' entry points for cPanel / WSGI / Passenger
app.secret_key = "slcat_topup_secret_key_2026_lk"
app.config["UPLOAD_FOLDER"] = UPLOAD_FOLDER
app.config["MAX_CONTENT_LENGTH"] = 10 * 1024 * 1024  # 10 MB max slip upload

# Initialize database tables on startup safely
try:
    init_db()
except Exception as e:
    logger.error(f"Database init warning: {e}")


# =====================================================================
# SECURITY & PERMANENT DEVICE / IP BAN ENFORCEMENT
# =====================================================================

@app.before_request
def security_and_ban_check():
    """Blocks any blacklisted device, IP, or user from accessing the store or APIs."""
    path = request.path
    if path.startswith("/static/") or path.startswith("/favicon.ico"):
        return None

    client_ip = request.headers.get("X-Forwarded-For", request.remote_addr)
    if client_ip and "," in client_ip:
        client_ip = client_ip.split(",")[0].strip()

    device_id = request.headers.get("X-Device-Id") or request.cookies.get("slcat_device_uuid")
    user_id = session.get("user_id")

    banned, reason = is_device_or_ip_banned(device_id, client_ip, user_id)
    if banned:
        if path.startswith("/api/"):
            return jsonify({
                "success": False,
                "error": "DEVICE_BANNED",
                "message": f"🚫 YOUR DEVICE/ACCOUNT IS PERMANENTLY BANNED: {reason}",
                "device_id": device_id,
                "ip": client_ip,
            }), 403
        else:
            return render_template(
                "banned.html",
                reason=reason,
                device_id=device_id or "DEVICE-BLOCKED",
                ip=client_ip,
            ), 403


# =====================================================================
# REAL-TIME VISITOR TRACKING & LIVE USER MONITORING
# =====================================================================

@app.before_request
def track_visitor_middleware():
    """Tracks visitor activity accurately for live online, daily, and all-time user metrics."""
    path = request.path
    # Ignore static files, admin internal polling APIs, and search engine crawler directives
    if (
        path.startswith("/static/")
        or path.startswith("/favicon.ico")
        or path.startswith("/api/admin/")
        or path in ("/robots.txt", "/sitemap.xml")
    ):
        return

    vid = request.cookies.get("slcat_vid")
    is_new = False
    if not vid or len(vid) < 10:
        vid = f"v_{uuid.uuid4().hex[:14]}"
        is_new = True
    g.visitor_id = vid
    g.is_new_vid = is_new

    try:
        user_id = session.get("user_id")
        ip = request.headers.get("CF-Connecting-IP") or request.headers.get("X-Forwarded-For", request.remote_addr)
        if ip and "," in ip:
            ip = ip.split(",")[0].strip()
        ua = request.headers.get("User-Agent", "")
        record_site_visitor(
            visitor_id=vid,
            ip=ip or "",
            user_agent=ua,
            path=path,
            user_id=user_id,
        )
    except Exception:
        pass


# =====================================================================
# 🔄 AUTOMATIC DYNAMIC ASSET VERSIONING & CACHE-BUSTING (AUTO-FIX ENGINE)
# =====================================================================
STATIC_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "static")

def get_asset_version() -> int:
    """Computes a dynamic asset version from the modification timestamp of static assets.
    Forces client browsers to immediately load fresh JS/CSS on any file update, preventing broken buttons.
    """
    try:
        main_js = os.path.join(STATIC_DIR, "js", "main.js")
        style_css = os.path.join(STATIC_DIR, "css", "style.css")
        mtimes = [
            os.path.getmtime(main_js) if os.path.exists(main_js) else 0,
            os.path.getmtime(style_css) if os.path.exists(style_css) else 0,
        ]
        return int(max(mtimes))
    except Exception:
        return int(time.time())


@app.context_processor
def inject_global_template_vars():
    """Injects dynamic asset version into all Jinja templates automatically."""
    return {
        "asset_version": get_asset_version(),
    }


@app.after_request
def set_visitor_cookie_header(response):
    """Ensures visitor ID cookie is set on client browsers for unique user counting."""
    if hasattr(g, "is_new_vid") and g.is_new_vid and hasattr(g, "visitor_id"):
        try:
            response.set_cookie(
                "slcat_vid",
                g.visitor_id,
                max_age=365 * 24 * 3600,
                httponly=True,
                samesite="Lax",
            )
        except Exception:
            pass
    # Prevent caching of dynamic HTML pages so browsers always fetch fresh buttons and scripts
    try:
        if hasattr(response, "mimetype") and response.mimetype == "text/html":
            response.headers["Cache-Control"] = "no-cache, no-store, must-revalidate, max-age=0"
            response.headers["Pragma"] = "no-cache"
            response.headers["Expires"] = "0"
    except Exception:
        pass
    return response


@app.route("/api/ping", methods=["POST", "GET"])
def api_visitor_ping():
    """Heartbeat ping from active customer browser tabs to keep live online count updated in real time."""
    return jsonify({"status": "ok"})


# =====================================================================
# SEO & SEARCH ENGINE INDEXING ROUTES
# =====================================================================

@app.route("/robots.txt")
def robots_txt():
    """Directs search engines to crawl public pages and discover sitemap."""
    content = """User-agent: *
Allow: /
Disallow: /admin
Disallow: /api/

Sitemap: https://topupshop.slcatvpn.bid/sitemap.xml
"""
    return Response(content, mimetype="text/plain")


@app.route("/sitemap.xml")
def sitemap_xml():
    """XML Sitemap submitted to Google Search Console for instant indexing."""
    xml = """<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <url>
    <loc>https://topupshop.slcatvpn.bid/</loc>
    <lastmod>2026-10-18</lastmod>
    <changefreq>daily</changefreq>
    <priority>1.0</priority>
  </url>
</urlset>"""
    return Response(xml, mimetype="application/xml")


# =====================================================================
# ⚡ QUICK PAY GATEWAY (INBOX & MANUAL ORDERS PAYMENT)
# =====================================================================

@app.route("/pay")
def quick_pay_page():
    """Direct standalone checkout page for inbox and manual top-up customers."""
    prefill_uid = request.args.get("uid", "").strip()
    prefill_amt = request.args.get("amt", "").strip()
    prefill_desc = request.args.get("desc") or request.args.get("note") or request.args.get("pkg") or "Inbox Custom Top-Up"
    prefill_phone = request.args.get("phone", "").strip()

    return render_template(
        "quick_pay.html",
        prefill_uid=prefill_uid,
        prefill_amt=prefill_amt,
        prefill_desc=prefill_desc,
        prefill_phone=prefill_phone,
        bank_accounts=BANK_ACCOUNTS,
        asset_version=int(time.time()),
    )


# =====================================================================
# CUSTOMER STOREFRONT ROUTES
# =====================================================================

@app.route("/")
def index():
    """Main customer storefront."""
    products = get_store_products()
    htg_stock_summary = {}
    try:
        stock_overview = get_all_products_live_stock()
        htg_stock_summary = stock_overview.get("summary", {})
        stock_map = stock_overview.get("products", {})
        for p in products:
            s_info = stock_map.get(str(p["id"]))
            if s_info:
                p["stock"] = s_info.get("stock", 0)
                p["stock_status"] = s_info.get("status", "out_of_stock")
                p["is_available"] = s_info.get("is_available", False)
                p["badge_text"] = s_info.get("badge_text")
                p["badge_sinhala"] = s_info.get("badge_sinhala")
                p["badge_color"] = s_info.get("badge_color", "#ef4444")
                p["htg_cost"] = s_info.get("htg_cost", 0.0)
            else:
                p["stock"] = 999
                p["stock_status"] = "in_stock"
                p["is_available"] = True
                p["badge_color"] = "#10b981"
    except Exception as e:
        logger.warning(f"Error enriching products with live stock: {e}")

    # Group products by category
    categories = {}
    for p in products:
        cat = p["category"]
        if cat not in categories:
            categories[cat] = []
    shop_settings = {
        "status": get_setting("shop_status", "open"),
        "open_time": get_setting("shop_open_time", "08:00 AM"),
        "close_time": get_setting("shop_close_time", "11:30 PM"),
        "notice": get_setting("shop_notice", "Shop is open. Instant delivery active!"),
    }
    current_user = None
    if session.get("user_id"):
        current_user = get_user_by_id(session["user_id"])

    coupons = get_all_coupons()
    active_coupons = [c for c in coupons if c.get("is_active")]

    # Calculate real-time delivery server low-balance restock status
    low_balance_threshold = 3000.0
    try:
        low_balance_threshold = float(get_setting("low_balance_threshold", "3000.0") or 3000.0)
    except Exception:
        low_balance_threshold = 3000.0

    eff_bal = float(htg_stock_summary.get("effective_balance_lkr", 0.0) or 0.0)
    in_stock_cnt = int(htg_stock_summary.get("in_stock_count", 0) or 0)
    is_low_balance = (eff_bal < low_balance_threshold) or (in_stock_cnt == 0 and len(products) > 0)

    return render_template(
        "index.html",
        categories=categories,
        products=products,
        shop_settings=shop_settings,
        current_user=current_user,
        active_coupons=active_coupons,
        bank_accounts=BANK_ACCOUNTS,
        htg_stock_summary=htg_stock_summary,
        is_low_balance=is_low_balance,
        low_balance_threshold=low_balance_threshold,
    )



@app.route("/api/stock_status", methods=["GET"])
def api_stock_status():
    """Public real-time endpoint returning live stock availability and restock alert status."""
    try:
        force = request.args.get("refresh", "").lower() in ("1", "true")
        stock_data = get_all_products_live_stock(force_refresh=force)
        summary = stock_data.get("summary", {})

        low_balance_threshold = 3000.0
        try:
            low_balance_threshold = float(get_setting("low_balance_threshold", "3000.0") or 3000.0)
        except Exception:
            low_balance_threshold = 3000.0

        eff_bal = float(summary.get("effective_balance_lkr", 0.0) or 0.0)
        in_stock_cnt = int(summary.get("in_stock_count", 0) or 0)
        total_items = int(summary.get("total_items", 0) or 0)

        is_low_balance = (eff_bal < low_balance_threshold) or (in_stock_cnt == 0 and total_items > 0)

        return jsonify({
            "success": True,
            "timestamp": stock_data.get("timestamp"),
            "summary": summary,
            "products": stock_data.get("products"),
            "is_low_balance": is_low_balance,
            "low_balance_threshold": low_balance_threshold,
            "effective_balance_lkr": eff_bal,
            "restock_notice": {
                "title": "සජීවී Server Balance නැවත පිරවීම (Restocking) සිදුවෙමින් පවතී",
                "message": "අපගේ Delivery Server Wallet ශේෂය නැවත Recharge වෙමින් පවතී. මෙම නිවේදනය ස්වයංක්‍රීයව ඉවත් වන තුරු (Auto-Clear වන තුරු) කරුණාකර නව Top-Up ඇණවුම් දැමීමෙන් වළකින්න. සර්වර් ශේෂය Recharge වූ සැණින් මෙම නිවේදනය ඉවත් වී ඇණවුම් භාරගැනීම සාමාන්‍ය පරිදි නැවත ආරම්භ වේ.",
                "auto_clears": True
            }
        })
    except Exception as e:
        logger.error(f"Error in api_stock_status: {e}")
        return jsonify({"success": False, "error": str(e)}), 500


@app.route("/api/bank_accounts", methods=["GET"])
def api_bank_accounts():
    """Returns all active store bank accounts for manual bank transfer."""
    return jsonify({
        "success": True,
        "accounts": BANK_ACCOUNTS,
    })


@app.route("/api/user/register", methods=["POST"])
def api_user_register():
    """Registers a new customer account using Name + Phone + 4-digit PIN + optional Gamer Avatar."""
    data = request.get_json(silent=True) or {}
    name = data.get("name", "")
    phone = data.get("phone", "")
    pin = data.get("pin", "")
    email = str(data.get("email", "")).strip().lower()
    avatar = data.get("avatar", "👤")

    result = register_user(name, phone, pin, email=email)
    if result.get("success"):
        session["user_id"] = result["user"]["id"]
        session["user_name"] = result["user"]["name"]
        session["user_phone"] = result["user"]["phone"]
        if email:
            session["user_email"] = email
        if avatar:
            try:
                from database import update_user_profile
                update_user_profile(result["user"]["id"], name=name, avatar=avatar)
                result["user"]["avatar"] = avatar
            except Exception:
                pass
        return jsonify(result), 200
    return jsonify(result), 400


@app.route("/api/user/login", methods=["POST"])
def api_user_login():
    """Authenticates a customer account or Admin using Phone/Username + 4-digit PIN."""
    data = request.get_json(silent=True) or {}
    raw_phone = str(data.get("phone", "")).strip()
    phone_clean = raw_phone.lower()
    pin = str(data.get("pin", "")).strip()
    remember = bool(data.get("remember_me"))

    admin_pin = get_setting("admin_pin", ADMIN_PIN)
    admin_phone = get_setting("admin_whatsapp_phone", "639104568696")

    # 1. Admin Login Detection (Support 'admin', 'adminiuhi', or admin phone)
    if (phone_clean in ("admin", "adminiuhi", "administrator", admin_phone.lower()) or phone_clean.startswith("admin")) and pin == admin_pin:
        session["admin_logged"] = True
        token_val = None
        if remember:
            session.permanent = True
            token_val = f"adm_{uuid.uuid4().hex}"
            set_setting("admin_remember_token", token_val)

        resp = jsonify({
            "success": True,
            "is_admin": True,
            "redirect": "/admin",
            "message": "👑 Welcome Admin (Crazy Owner)! Redirecting to Dashboard..."
        })
        if token_val:
            resp.set_cookie("slcat_admin_token", token_val, max_age=30*24*3600, httponly=True, samesite="Lax")
        return resp, 200

    # 2. Customer Authentication
    result = authenticate_user(raw_phone, pin)
    if result.get("success"):
        session["user_id"] = result["user"]["id"]
        session["user_name"] = result["user"]["name"]
        session["user_phone"] = result["user"]["phone"]
        if remember:
            session.permanent = True
        return jsonify(result), 200
    return jsonify(result), 400


@app.route("/api/user/forgot_pin", methods=["POST"])
def api_user_forgot_pin():
    """Allows customer to self-reset their forgotten PIN using phone + Free Fire UID or past Order Code."""
    data = request.get_json(silent=True) or {}
    phone = str(data.get("phone", "")).strip()
    verify_val = str(data.get("verify_value", "")).strip()
    new_pin = str(data.get("new_pin", "")).strip()
    confirm_pin = str(data.get("confirm_pin", "")).strip()

    if not phone:
        return jsonify({"success": False, "message": "කරුණාකර ඔබගේ ලියාපදිංචි දුරකථන අංකය ඇතුළත් කරන්න."}), 400
    if not verify_val:
        return jsonify({"success": False, "message": "කරුණාකර ඔබගේ Free Fire UID (Player ID) හෝ පෙර Order Code එක ඇතුළත් කරන්න."}), 400
    if not new_pin or len(new_pin) != 4 or not new_pin.isdigit():
        return jsonify({"success": False, "message": "නව PIN අංකය ඉලක්කම් 4කින් සමන්විත විය යුතුය (උදා: 1234)."}), 400
    if new_pin != confirm_pin:
        return jsonify({"success": False, "message": "නව PIN අංකය තහවුරු කළ PIN අංකයට සමාන නොවේ (PIN mismatch)."}), 400

    result = reset_user_pin_verified(phone, verify_val, new_pin)
    if result.get("success"):
        # Auto-login after successful reset
        user_data = result.get("user")
        if user_data:
            session["user_id"] = user_data["id"]
            session["user_name"] = user_data["name"]
            session["user_phone"] = user_data["phone"]
        return jsonify(result), 200
    return jsonify(result), 400


@app.route("/api/user/logout", methods=["POST", "GET"])
def api_user_logout():
    """Logs out the customer."""
    session.pop("user_id", None)
    session.pop("user_name", None)
    session.pop("user_phone", None)
    session.pop("user_email", None)
    return jsonify({"success": True, "message": "Logged out successfully"})


@app.route("/api/user/email/send_otp", methods=["POST"])
def api_user_email_send_otp():
    """Generates and sends a 6-digit OTP code to the requested email for verification."""
    user_id = session.get("user_id")
    if not user_id:
        return jsonify({"success": False, "message": "කරුණාකර පළමුව Login වන්න (Please login first)."}), 401

    data = request.get_json(silent=True) or {}
    email = str(data.get("email", "")).strip().lower()

    if not email or "@" not in email or "." not in email:
        return jsonify({"success": False, "message": "වලංගු Email ලිපිනයක් ඇතුළත් කරන්න (Valid email required)."}), 400

    user = get_user_by_id(user_id)
    if not user:
        return jsonify({"success": False, "message": "User not found"}), 404

    # Generate secure 6-digit OTP
    import random
    otp_code = str(random.randint(100000, 999999))

    ok = set_user_email_otp(user_id, email, otp_code, expiry_minutes=10)
    if not ok:
        return jsonify({"success": False, "message": "OTP සුරැකීම අසාර්ථක විය."}), 500

    from mail_service import get_smtp_password, send_otp_email_sync_with_status
    pwd = get_smtp_password()
    if not pwd:
        return jsonify({
            "success": False,
            "message": "⚠️ Gmail SMTP සක්‍රීය කර නැත! Admin Panel වෙත ගොස් slcatapp@gmail.com සඳහා Google 16-Letter App Password එක Save කරන්න."
        }), 400

    # Send email with immediate status feedback
    sent, err_msg = send_otp_email_sync_with_status(email, otp_code, user_name=user.get("name", ""))
    if not sent:
        return jsonify({
            "success": False,
            "message": f"❌ Email එක යැවීම අසාර්ථක විය: {err_msg}"
        }), 500

    return jsonify({
        "success": True,
        "message": f"OTP අංකය `{email}` ලිපිනයට සාර්ථකව යවන ලදී! කරුණාකර Inbox හෝ Spam පරීක්ෂා කරන්න.",
        "email": email,
    })


@app.route("/api/user/email/verify_otp", methods=["POST"])
def api_user_email_verify_otp():
    """Verifies the 6-digit OTP code and marks user email as verified."""
    user_id = session.get("user_id")
    if not user_id:
        return jsonify({"success": False, "message": "කරුණාකර පළමුව Login වන්න."}), 401

    data = request.get_json(silent=True) or {}
    email = str(data.get("email", "")).strip().lower()
    otp = str(data.get("otp", "")).strip()

    if not email or not otp:
        return jsonify({"success": False, "message": "Email ලිපිනය සහ 6-Digit OTP අංකය ඇතුළත් කරන්න."}), 400

    res = verify_user_email_otp(user_id, email, otp)
    if res.get("success"):
        session["user_email"] = email
        return jsonify(res), 200
    return jsonify(res), 400


@app.route("/api/user/me", methods=["GET"])
def api_user_me():
    """Returns profile of currently logged-in customer."""
    user_id = session.get("user_id")
    if not user_id:
        return jsonify({"authenticated": False})
    user = get_user_by_id(user_id)
    if not user:
        session.pop("user_id", None)
        return jsonify({"authenticated": False})
    return jsonify({"authenticated": True, "user": user})


@app.route("/api/user/profile/update", methods=["POST"])
def api_user_profile_update():
    """Updates customer's display name, avatar, email, and optionally changes their 4-digit PIN."""
    user_id = session.get("user_id")
    if not user_id:
        return jsonify({"success": False, "message": "කරුණාකර පළමුව Login වන්න."}), 401
    data = request.get_json(silent=True) or {}
    name = data.get("name", "")
    avatar = data.get("avatar", "👤")
    email = data.get("email")
    current_pin = data.get("current_pin", "")
    new_pin = data.get("new_pin", "")

    res = update_user_profile(
        user_id=user_id,
        name=name,
        avatar=avatar,
        current_pin=current_pin,
        new_pin=new_pin,
        email=email,
    )
    if res.get("success"):
        session["user_name"] = res.get("name", name)
        if "email" in res:
            session["user_email"] = res.get("email")
    return jsonify(res)


@app.route("/api/user/orders", methods=["GET"])
def api_user_orders():
    """Returns order history for the logged-in customer."""
    user_id = session.get("user_id")
    if not user_id:
        return jsonify({"success": False, "message": "කරුණාකර පළමුව Login වන්න."}), 401
    orders = get_user_orders(user_id)
    return jsonify({"success": True, "orders": orders})


@app.route("/api/user/wallet", methods=["GET"])
def api_user_wallet():
    """Returns customer wallet balance and transactions."""
    user_id = session.get("user_id")
    if not user_id:
        return jsonify({"authenticated": False, "balance": 0.0}), 200

    balance = get_user_wallet_balance(user_id)
    transactions = get_wallet_transactions(user_id, limit=30)
    return jsonify({
        "success": True,
        "authenticated": True,
        "balance": balance,
        "balance_formatted": f"Rs. {balance:,.2f}",
        "transactions": transactions,
    })


@app.route("/api/user/wallet/deposit", methods=["POST"])
def api_user_wallet_deposit():
    """Generates Dynamic LankaQR for depositing money into user's wallet."""
    if get_setting("shop_status", "open") == "closed":
        open_time = get_setting("shop_open_time", "08:00 AM")
        return jsonify({
            "success": False,
            "shop_closed": True,
            "message": f"🚫 කඩය මේ වන විට වසා ඇත (Shop Closed). නැවත විවෘත වන්නේ {open_time} ටයි.",
        }), 403

    user_id = session.get("user_id")
    if not user_id:
        return jsonify({"success": False, "message": "කරුණාකර පළමුව Login වන්න."}), 401

    user = get_user_by_id(user_id)
    data = request.get_json(silent=True) or {}
    try:
        amount = float(data.get("amount", 0.0))
    except (ValueError, TypeError):
        amount = 0.0

    if amount < 50:
        return jsonify({"success": False, "message": "අවම Deposit මුදල රු. 50.00 කි."}), 400

    base_amount = round(amount, 2)
    total_amount = generate_unique_order_amount(base_amount)
    cents_fee = round(total_amount - base_amount, 2)

    qr_payload = get_dynamic_lankaqr(total_amount)
    qr_base64 = generate_qr_base64(qr_payload)

    order_code = create_order(
        player_id=f"WALLET-{user_id}",
        nickname=user["name"] if user else "Wallet User",
        product_id="wallet_deposit",
        product_name=f"Wallet Top-Up (Rs. {base_amount:,.2f})",
        amount=total_amount,
        qr_payload=qr_payload,
        quantity=1,
        user_id=user_id,
        customer_name=user["name"] if user else None,
        customer_phone=user["phone"] if user else None,
    )

    return jsonify({
        "success": True,
        "order_code": order_code,
        "product_name": f"Wallet Top-Up (Rs. {base_amount:,.2f})",
        "base_amount": base_amount,
        "cents_fee": cents_fee,
        "amount": total_amount,
        "amount_formatted": f"Rs. {total_amount:,.2f}",
        "qr_base64": qr_base64,
        "qr_payload": qr_payload,
        "expires_in_seconds": 900,
    })


@app.route("/api/order/pay_wallet", methods=["POST"])
def api_order_pay_wallet():
    """Instant 1-Click purchase using Wallet Balance (No QR scan needed)."""
    try:
        if get_setting("shop_status", "open") == "closed":
            open_time = get_setting("shop_open_time", "08:00 AM")
            return jsonify({
                "success": False,
                "shop_closed": True,
                "message": f"🚫 කඩය මේ වන විට වසා ඇත (Shop Closed). නැවත විවෘත වන්නේ {open_time} ටයි.",
            }), 403

        user_id = session.get("user_id")
        if not user_id:
            return jsonify({"success": False, "message": "Wallet එකෙන් ගෙවීමට කරුණාකර පළමුව Login වන්න."}), 401

        user = get_user_by_id(user_id)
        data = request.get_json(silent=True) or {}
        order_code = str(data.get("order_code", "")).strip()
        raw_items = data.get("items")
        items_json = None

        existing_order = get_order(order_code) if order_code else None

        if existing_order:
            player_id = existing_order["player_id"]
            nickname = existing_order.get("nickname") or ""
            product_id = existing_order["product_id"]
            product_name = existing_order["product_name"]
            quantity = existing_order.get("quantity", 1)
            items_json = existing_order.get("items_json")
            if items_json and not raw_items:
                try:
                    raw_items = json.loads(items_json)
                except Exception:
                    pass

            if product_id == "cart_multi":
                total_amount = round(float(existing_order.get("amount") or 0.0), 2)
            else:
                # Charge exact base price for wallet users (no bank cents fee)
                unit_price = get_product_price(product_id)
                total_amount = round(unit_price * quantity, 2)
                with get_connection() as conn:
                    conn.cursor().execute("UPDATE orders SET amount = ? WHERE order_code = ?", (total_amount, order_code))
                    conn.commit()
        else:
            player_id = str(data.get("player_id", "")).strip()
            nickname = str(data.get("nickname", "")).strip()

            if raw_items and isinstance(raw_items, list) and len(raw_items) > 0:
                total_amount = 0.0
                item_names = []
                total_qty = 0
                items_list = []
                for itm in raw_items:
                    pid = str(itm.get("product_id") or itm.get("id") or "").strip()
                    qty = max(1, int(itm.get("quantity") or itm.get("qty") or 1))
                    prod = next((p for p in PRODUCT_CATALOG if p["id"] == pid), None)
                    if prod:
                        u_price = get_product_price(pid)
                        total_amount += u_price * qty
                        total_qty += qty
                        item_names.append(f"{prod['name']} (x{qty})")
                        items_list.append({
                            "product_id": pid,
                            "name": prod["name"],
                            "quantity": qty,
                            "unit_price": u_price,
                            "total_price": round(u_price * qty, 2),
                        })
                if not items_list:
                    return jsonify({"success": False, "message": "වලංගු Package තෝරාගෙන නොමැත."}), 400

                product_id = "cart_multi"
                product_name = " + ".join(item_names[:3])
                if len(item_names) > 3:
                    product_name += f" + {len(item_names) - 3} more"
                quantity = total_qty
                items_json = json.dumps(items_list)
                total_amount = round(total_amount, 2)
            else:
                product_id = str(data.get("product_id", "")).strip()
                quantity = int(data.get("quantity", 1))

                if not player_id or not product_id:
                    return jsonify({"success": False, "message": "Player ID සහ Package එකක් තෝරන්න."}), 400

                product = next((p for p in PRODUCT_CATALOG if p["id"] == product_id), None)
                if not product:
                    return jsonify({"success": False, "message": "වලංගු නොවන Package එකකි."}), 400

                unit_price = get_product_price(product_id)
                total_amount = round(unit_price * quantity, 2)
                product_name = product["name"]

        # Real-Time Stock Validation Guardrail (excludes current order from reserved balance to avoid self-locking)
        stock_valid, stock_msg, stock_details = validate_order_stock(
            product_id=product_id if not raw_items else None,
            quantity=quantity if not raw_items else 1,
            items=raw_items if raw_items else None,
            exclude_order_code=order_code if order_code else None,
        )
        if not stock_valid:
            return jsonify({
                "success": False,
                "out_of_stock": True,
                "message": stock_msg,
                "stock_details": stock_details,
            }), 400

        # Check and debit wallet
        debit_res = debit_wallet(
            user_id=user_id,
            amount=total_amount,
            description=f"Top-Up: {product_name} (UID: {player_id})",
            reference_code=order_code or "",
        )

        if not debit_res.get("success"):
            return jsonify(debit_res), 400

        if not existing_order:
            # Create completed order in database
            order_code = create_order(
                player_id=player_id,
                nickname=nickname,
                product_id=product_id,
                product_name=product_name,
                amount=total_amount,
                qr_payload="PAID_VIA_WALLET",
                quantity=quantity,
                user_id=user_id,
                customer_name=user.get("name") if user else None,
                customer_phone=user.get("phone") if user else None,
                items_json=items_json,
            )

        update_order_payment(order_code, tx_reference=f"WALLET-BAL-{int(time.time())}")
        update_user_saved_uid(user_id, player_id, nickname)

        # Instant HTG delivery
        delivery_res = process_and_deliver_order(order_code)

        return jsonify({
            "success": True,
            "order_code": order_code,
            "product_name": product_name,
            "amount": total_amount,
            "amount_formatted": f"Rs. {total_amount:,.2f}",
            "new_wallet_balance": debit_res.get("new_balance"),
            "delivery": delivery_res,
        })
    except Exception as e:
        return jsonify({"success": False, "message": f"Wallet Payment Error: {str(e)}"}), 500



@app.route("/api/check_uid", methods=["POST"])
def api_check_uid():
    """Validates Free Fire Player ID and returns nickname."""
    data = request.get_json() or {}
    uid = str(data.get("uid", "")).strip()
    if not uid:
        return jsonify({"success": False, "message": "Player ID ඇතුළත් කරන්න."}), 400

    result = check_player_uid(uid)
    return jsonify(result)


@app.route("/api/shop_status", methods=["GET"])
def api_public_shop_status():
    """Public endpoint to check if the store is currently open."""
    status = get_setting("shop_status", "open")
    open_time = get_setting("shop_open_time", "08:00 AM")
    close_time = get_setting("shop_close_time", "11:30 PM")
    return jsonify({
        "status": status,
        "is_open": status != "closed",
        "open_time": open_time,
        "close_time": close_time,
    })


@app.route("/api/coupon/validate", methods=["POST"])
def api_validate_coupon():
    """Validates coupon code against order amount."""
    data = request.get_json(silent=True) or {}
    code = str(data.get("coupon_code", "")).strip().upper()
    try:
        amount = float(data.get("amount", 0.0))
    except (ValueError, TypeError):
        amount = 0.0
    res = validate_coupon(code, amount)
    return jsonify(res)


@app.route("/api/create_order", methods=["POST"])
def api_create_order():
    """
    Creates an order and returns Dynamic LankaQR with exact locked amount.
    Supports Promo/Coupon codes and device fingerprinting.
    """
    if get_setting("shop_status", "open") == "closed":
        open_time = get_setting("shop_open_time", "08:00 AM")
        return jsonify({
            "success": False,
            "shop_closed": True,
            "message": f"🚫 කඩය මේ වන විට වසා ඇත (Shop Closed). නැවත විවෘත වන්නේ {open_time} ටයි. කරුණාකර පසුව පැමිණෙන්න."
        }), 403

    data = request.get_json() or {}
    player_id = str(data.get("player_id", "")).strip()
    nickname = str(data.get("nickname", "")).strip()
    coupon_code = str(data.get("coupon_code", "")).strip().upper()
    device_id = str(data.get("device_id") or request.headers.get("X-Device-Id") or request.cookies.get("slcat_device_uuid") or "")

    raw_items = data.get("items")
    items_json = None
    items_list = []

    if raw_items and isinstance(raw_items, list) and len(raw_items) > 0:
        if not player_id:
            return jsonify({"success": False, "message": "Player Free Fire UID එක ඇතුළත් කරන්න."}), 400

        base_amount = 0.0
        item_names = []
        total_qty = 0
        for itm in raw_items:
            pid = str(itm.get("product_id") or itm.get("id") or "").strip()
            qty = max(1, int(itm.get("quantity") or itm.get("qty") or 1))
            prod = next((p for p in PRODUCT_CATALOG if p["id"] == pid), None)
            if prod:
                u_price = get_product_price(pid)
                base_amount += u_price * qty
                total_qty += qty
                item_names.append(f"{prod['name']} (x{qty})")
                items_list.append({
                    "product_id": pid,
                    "name": prod["name"],
                    "quantity": qty,
                    "unit_price": u_price,
                    "total_price": round(u_price * qty, 2),
                })
        if not items_list:
            return jsonify({"success": False, "message": "වලංගු Package තෝරාගෙන නොමැත."}), 400

        product_id = "cart_multi"
        product_name = " + ".join(item_names[:3])
        if len(item_names) > 3:
            product_name += f" + {len(item_names) - 3} more"
        quantity = total_qty
        items_json = json.dumps(items_list)
        base_amount = round(base_amount, 2)
    else:
        product_id = str(data.get("product_id", "")).strip()
        quantity = int(data.get("quantity", 1))

        if not player_id or not product_id:
            return jsonify({"success": False, "message": "Player ID සහ Package එකක් තෝරන්න."}), 400

        # Find product info
        product = next((p for p in PRODUCT_CATALOG if p["id"] == product_id), None)
        if not product:
            return jsonify({"success": False, "message": "වලංගු නොවන Package එකකි."}), 400

        unit_price = get_product_price(product_id)
        base_amount = round(unit_price * quantity, 2)
        product_name = product["name"]
        items_list = [{
            "product_id": product_id,
            "name": product_name,
            "quantity": quantity,
            "unit_price": unit_price,
            "total_price": base_amount,
        }]

    # Real-Time Stock Validation Guardrail
    stock_valid, stock_msg, stock_details = validate_order_stock(
        product_id=product_id if not raw_items else None,
        quantity=quantity if not raw_items else 1,
        items=raw_items if raw_items else None,
    )
    if not stock_valid:
        return jsonify({
            "success": False,
            "out_of_stock": True,
            "message": stock_msg,
            "stock_details": stock_details,
        }), 400

    discount_amount = 0.0

    # Validate coupon if provided
    if coupon_code:
        c_res = validate_coupon(coupon_code, base_amount)
        if c_res.get("valid"):
            discount_amount = float(c_res.get("discount_amount", 0.0))
            base_amount = max(1.0, round(base_amount - discount_amount, 2))
            record_coupon_usage(coupon_code)
        else:
            coupon_code = None

    # Dynamic unique verification cents (Method 2) for 100% collision-free auto-match
    total_amount = generate_unique_order_amount(base_amount)
    cents_fee = round(total_amount - base_amount, 2)

    # 1. Generate dynamic LankaQR locked to exact total_amount
    qr_payload = get_dynamic_lankaqr(total_amount)
    qr_base64 = generate_qr_base64(qr_payload)

    # User profile integration
    user_id = session.get("user_id")
    customer_name = session.get("user_name") or data.get("customer_name")
    customer_phone = session.get("user_phone") or data.get("customer_phone")

    if user_id and player_id:
        try:
            update_user_saved_uid(user_id, player_id, nickname)
        except Exception:
            pass

    # 2. Save order in database with coupon, discount and device info
    order_code = create_order(
        player_id=player_id,
        nickname=nickname,
        product_id=product_id,
        product_name=product_name,
        amount=total_amount,
        qr_payload=qr_payload,
        quantity=quantity,
        user_id=user_id,
        customer_name=customer_name,
        customer_phone=customer_phone,
        coupon_code=coupon_code,
        discount_amount=discount_amount,
        device_id=device_id,
        items_json=items_json,
    )

    return jsonify({
        "success": True,
        "order_code": order_code,
        "product_name": product_name,
        "base_amount": base_amount,
        "discount_amount": discount_amount,
        "coupon_code": coupon_code,
        "cents_fee": cents_fee,
        "amount": total_amount,
        "amount_formatted": f"Rs. {total_amount:,.2f}",
        "qr_base64": qr_base64,
        "qr_payload": qr_payload,
        "expires_in_seconds": 900,  # 15 minutes QR validity (auto-reject after 15 mins)
        "items": items_list,
    })


@app.route("/api/quick_pay/create_order", methods=["POST"])
def api_quick_pay_create_order():
    """Generates an order & dynamic LankaQR for quick pay customers."""
    data = request.get_json(silent=True) or {}
    player_id = str(data.get("player_id", "")).strip()
    nickname = str(data.get("nickname", "Player")).strip()
    description = str(data.get("description", "Inbox Custom Top-Up")).strip() or "Inbox Custom Top-Up"
    customer_phone = str(data.get("customer_phone", "")).strip()
    customer_name = str(data.get("customer_name", "Inbox Customer")).strip()
    customer_email = str(data.get("customer_email", "")).strip()

    try:
        base_amount = float(data.get("amount", 0.0))
    except (ValueError, TypeError):
        return jsonify({"success": False, "message": "වලංගු මුදලක් ඇතුළත් කරන්න."}), 400

    if not player_id:
        return jsonify({"success": False, "message": "Player UID එක ඇතුළත් කරන්න."}), 400

    if base_amount < 10.0:
        return jsonify({"success": False, "message": "අවම මුදල රු. 10.00 කි."}), 400

    # Auto-verify nickname if missing
    if not nickname or nickname == "Player":
        try:
            u_res = check_player_uid(player_id)
            if u_res and u_res.get("nickname"):
                nickname = u_res["nickname"]
        except Exception:
            pass

    # Dynamic unique verification cents for collision-free auto-match
    total_amount = generate_unique_order_amount(base_amount)

    # 1. Generate dynamic LankaQR
    qr_payload = get_dynamic_lankaqr(total_amount)
    qr_base64 = generate_qr_base64(qr_payload)

    # 2. Save order in database with custom inbox flag
    order_code = create_order(
        player_id=player_id,
        nickname=nickname,
        product_id="inbox_custom",
        product_name=f"[INBOX] {description}",
        amount=total_amount,
        qr_payload=qr_payload,
        quantity=1,
        customer_name=customer_name,
        customer_phone=customer_phone,
    )

    if customer_email and "@" in customer_email:
        try:
            with get_connection() as conn:
                conn.cursor().execute("UPDATE orders SET customer_email = ? WHERE order_code = ?", (customer_email, order_code))
                conn.commit()
        except Exception:
            pass

    return jsonify({
        "success": True,
        "order_code": order_code,
        "product_name": description,
        "base_amount": base_amount,
        "amount": total_amount,
        "amount_formatted": f"Rs. {total_amount:,.2f}",
        "qr_base64": qr_base64,
        "qr_payload": qr_payload,
        "expires_in_seconds": 900,
    })


@app.route("/api/admin/generate_pay_link", methods=["POST"])
def api_admin_generate_pay_link():
    """Generates a shareable Quick Pay link for Admin to send via WhatsApp or SMS."""
    if not is_admin_authorized():
        return jsonify({"success": False, "message": "Unauthorized"}), 401

    data = request.get_json(silent=True) or {}
    player_id = str(data.get("player_id", "")).strip()
    desc = str(data.get("description", "Free Fire Diamonds")).strip()
    phone = str(data.get("customer_phone", "")).strip()

    try:
        amount = float(data.get("amount", 0.0))
    except (ValueError, TypeError):
        return jsonify({"success": False, "message": "වලංගු මුදලක් ඇතුළත් කරන්න."}), 400

    params = {}
    if player_id:
        params["uid"] = player_id
    if amount > 0:
        params["amt"] = int(amount) if amount.is_integer() else amount
    if desc:
        params["desc"] = desc
    if phone:
        params["phone"] = phone

    base_url = "https://topupshop.slcatvpn.bid/pay"
    query_str = urllib.parse.urlencode(params)
    pay_url = f"{base_url}?{query_str}" if query_str else base_url

    wa_text = f"ආයුබෝවන්! ඔබගේ Free Fire Top-Up ඇණවුම ({desc}) සඳහා ගෙවීම සිදුකිරීමට පහත නිල Payment Gateway Link එක භාවිතා කරන්න:\n\n👉 {pay_url}\n\n(LankaQR හෝ Bank Transfer මඟින් තත්පර 15න් ගෙවිය හැක)\nස්තුතියි! - SL CAT TOPUP"
    wa_share_url = f"https://wa.me/{phone if phone else ''}?text={urllib.parse.quote(wa_text)}"

    return jsonify({
        "success": True,
        "payment_url": pay_url,
        "whatsapp_share_url": wa_share_url,
        "message_text": wa_text,
    })


# -------------------------------------------------------------
# MANU TOPUP (manutopup.com) API INTEGRATION
# -------------------------------------------------------------
@app.route("/api/manu/packages", methods=["GET"])
def api_manu_packages():
    """Returns available packages on manutopup.com with live pricing."""
    pkgs = []
    for pid, info in MANU_PACKAGES_MAP.items():
        pkgs.append({
            "id": pid,
            "name": info["name"],
            "price": info["price"],
            "category": info.get("category", "General")
        })
    return jsonify({"success": True, "packages": pkgs})


@app.route("/api/manu/check_uid", methods=["POST"])
def api_manu_check_uid():
    """Validates Free Fire Player UID using Manu Topup's verification engine."""
    data = request.get_json(silent=True) or {}
    uid = str(data.get("uid", "")).strip()
    region = str(data.get("region", "SG")).strip()
    res = verify_player_uid_manu(uid, region=region)
    return jsonify(res)


@app.route("/api/manu/create_order", methods=["POST"])
def api_manu_create_order():
    """Dispatches a Free Fire top-up order directly to manutopup.com."""
    if not is_admin_authorized():
        return jsonify({"success": False, "message": "Admin authorization required"}), 401

    data = request.get_json(silent=True) or {}
    player_id = str(data.get("player_id", "")).strip()
    product_id = str(data.get("product_id", "")).strip()
    quantity = int(data.get("quantity", 1))
    customer_phone = str(data.get("customer_phone", "")).strip() or "0771234567"
    customer_email = str(data.get("customer_email", "slcatreseller@gmail.com")).strip()
    customer_name = str(data.get("customer_name", "SL CAT Store")).strip()
    payment_method = str(data.get("payment_method", "card")).strip()
    firebase_uid = data.get("firebase_uid")

    if not player_id or not product_id:
        return jsonify({"success": False, "message": "Player UID and Product ID are required."}), 400

    result = create_manu_order(
        player_id=player_id,
        product_id=product_id,
        quantity=quantity,
        customer_phone=customer_phone,
        customer_email=customer_email,
        customer_name=customer_name,
        payment_method=payment_method,
        firebase_uid=firebase_uid
    )
    return jsonify(result)


@app.route("/api/manu/check_status/<order_id>", methods=["GET"])
def api_manu_check_status(order_id):
    """Checks fulfillment status of an order on manutopup.com."""
    res = check_manu_order_status(order_id)
    return jsonify(res)


@app.route("/api/manu/orders", methods=["GET"])
def api_manu_get_orders():
    """Fetches order history by email from manutopup.com."""
    email = request.args.get("email", "slcatreseller@gmail.com")
    res = get_manu_orders_by_email(email)
    return jsonify(res)


@app.route("/api/manu/whatsapp_link", methods=["POST"])
def api_manu_whatsapp_link():
    """Generates direct WhatsApp order link to Manu Topup Admin (+94 72 935 1052)."""
    data = request.get_json(silent=True) or {}
    player_uid = str(data.get("player_uid", "")).strip()
    package_name = str(data.get("package_name", "Free Fire Diamonds")).strip()
    try:
        amount = float(data.get("amount", 0.0))
    except (ValueError, TypeError):
        amount = 0.0
    order_id = data.get("order_id")

    wa_link = generate_manu_whatsapp_link(player_uid, package_name, amount, order_id)
    return jsonify({"success": True, "whatsapp_link": wa_link})


@app.route("/api/submit_payment", methods=["POST"])
def api_submit_payment():
    """Client submits payment reference or deposit slip."""
    order_code = request.form.get("order_code")
    tx_reference = request.form.get("tx_reference", "").strip()
    slip_file = request.files.get("slip_file")

    if not order_code:
        return jsonify({"success": False, "message": "Order Code එකක් නොමැත."}), 400

    order = get_order(order_code)
    if not order:
        return jsonify({"success": False, "message": "Order එක සොයාගත නොහැකි විය."}), 404

    slip_filename = None
    slip_hash = None
    slip_dhash = None
    if slip_file and slip_file.filename:
        slip_bytes = slip_file.read()
        slip_file.seek(0)

        # File size safety check (less than 1KB is corrupt or fake)
        if len(slip_bytes) < 1024:
            return jsonify({
                "success": False,
                "message": "⚠️ ඔබ Upload කළ Receipt පත වලංගු නොවේ (File size too small). කරුණාකර පැහැදිලි Bank Receipt එකක් Upload කරන්න."
            }), 400

        slip_hash = hashlib.sha256(slip_bytes).hexdigest()
        slip_dhash = compute_image_dhash(slip_bytes)

        # Anti-Fraud & Duplicate Re-Order Check (SHA-256 + Perceptual dHash)
        is_dup, dup_msg, dup_order, dup_type = check_duplicate_slip(
            slip_hash=slip_hash,
            slip_dhash=slip_dhash,
            exclude_order_code=order_code
        )
        if is_dup:
            orig_code = dup_order.get("order_code") if dup_order else ""
            if dup_type == "pending_reorder":
                logger.info(f"Duplicate re-order auto-merged: order {order_code} is a duplicate of pending order {orig_code}.")
                # 1. Auto-cancel this newly created duplicate order so admin doesn't see ghost/double orders
                with get_connection() as conn:
                    cursor = conn.cursor()
                    cursor.execute(
                        "UPDATE orders SET status = 'cancelled', error_message = ? WHERE order_code = ?",
                        (f"ස්වයංක්‍රීයව අවලංගු විය: පෙර ඇණවුමේ ({orig_code}) අනුපිටපතකි (Duplicate re-order)", order_code),
                    )
                    conn.commit()

                # 2. Make sure original order has the slip & is marked payment_submitted for admin attention
                orig_order = get_order(orig_code)
                if orig_order and orig_order.get("status") in ("failed", "pending_payment", "awaiting_bank_confirmation", "payment_submitted"):
                    filename = secure_filename(f"{orig_code}_{int(time.time())}_{slip_file.filename}")
                    save_path = os.path.join(app.config["UPLOAD_FOLDER"], filename)
                    slip_file.save(save_path)
                    saved_path = f"uploads/{filename}"
                    update_order_payment(
                        orig_code,
                        tx_reference=tx_reference or orig_order.get("tx_reference"),
                        slip_path=orig_order.get("slip_path") or saved_path,
                        slip_hash=orig_order.get("slip_hash") or slip_hash,
                        slip_dhash=orig_order.get("slip_dhash") or slip_dhash,
                    )

                return jsonify({
                    "success": False,
                    "is_duplicate_reorder": True,
                    "original_order_code": orig_code,
                    "message": dup_msg,
                    "redirect_url": f"/order/{orig_code}",
                }), 200
            else:
                logger.warning(f"Anti-Fraud Guard: Attempted reuse of already completed slip for order {order_code} (matched {orig_code})")
                return jsonify({
                    "success": False,
                    "security_blocked": True,
                    "is_already_completed": True,
                    "original_order_code": orig_code,
                    "message": f"🚨 ආරක්ෂක පද්ධතිය මඟින් ප්‍රතික්ෂේප විය:\n{dup_msg}",
                }), 400

        filename = secure_filename(f"{order_code}_{int(time.time())}_{slip_file.filename}")
        save_path = os.path.join(app.config["UPLOAD_FOLDER"], filename)
        slip_file.save(save_path)
        slip_filename = f"uploads/{filename}"

    if not tx_reference and not slip_filename:
        return jsonify({"success": False, "message": "කරුණාකර Reference අංකය හෝ Receipt එක Upload කරන්න."}), 400

    # If manual tx_reference provided, check for duplicates
    if tx_reference:
        is_dup_ref, dup_ref_msg, dup_ref_order, dup_ref_type = check_duplicate_slip(tx_reference=tx_reference, exclude_order_code=order_code)
        if is_dup_ref:
            orig_ref_code = dup_ref_order.get("order_code") if dup_ref_order else ""
            if dup_ref_type == "pending_reorder":
                with get_connection() as conn:
                    cursor = conn.cursor()
                    cursor.execute(
                        "UPDATE orders SET status = 'cancelled', error_message = ? WHERE order_code = ?",
                        (f"ස්වයංක්‍රීයව අවලංගු විය: පෙර ඇණවුමේ ({orig_ref_code}) Reference අනුපිටපතකි", order_code),
                    )
                    conn.commit()
                return jsonify({
                    "success": False,
                    "is_duplicate_reorder": True,
                    "original_order_code": orig_ref_code,
                    "message": dup_ref_msg,
                    "redirect_url": f"/order/{orig_ref_code}",
                }), 200
            else:
                return jsonify({
                    "success": False,
                    "security_blocked": True,
                    "is_already_completed": True,
                    "original_order_code": orig_ref_code,
                    "message": f"🚨 ආරක්ෂක පද්ධතිය මඟින් ප්‍රතික්ෂේප විය:\n{dup_ref_msg}",
                }), 400

    # If slip was uploaded and no ref was entered, optionally attempt Gemini Vision extraction
    if slip_filename and not tx_reference:
        try:
            from ai_assistant import extract_slip_info_with_gemini
            slip_abs_path = os.path.join(app.config["UPLOAD_FOLDER"], filename)
            extracted = extract_slip_info_with_gemini(slip_abs_path)
            if extracted and extracted.get("ref_id"):
                extracted_ref = str(extracted["ref_id"]).strip()
                is_dup_ext, dup_ext_msg, _, _ = check_duplicate_slip(tx_reference=extracted_ref, exclude_order_code=order_code)
                if not is_dup_ext:
                    tx_reference = extracted_ref
        except Exception:
            pass

    update_order_payment(order_code, tx_reference=tx_reference, slip_path=slip_filename, slip_hash=slip_hash, slip_dhash=slip_dhash)

    # 1. Immediate match check with pending bank notification (Method 2 cents-match)
    match = find_matching_notification(order["amount"])
    if match:
        mark_notification_matched(match["id"], order_code)
        fulfill_res = process_and_deliver_order(order_code)
        if fulfill_res.get("success"):
            return jsonify({
                "success": True,
                "message": "ගෙවීම ස්වයංක්‍රීයව තහවුරු විය! ඔබගේ Diamonds සාර්ථකව Deliver කරන ලදී! 💎",
                "order_code": order_code,
                "auto_delivered": True,
            })

    return jsonify({
        "success": True,
        "message": "Payment එක සාර්ථකව Submit විය. තත්පර කිහිපයකින් ක්‍රියාත්මක වේ.",
        "order_code": order_code,
        "auto_delivered": False,
    })


# =========================================================================
# 🎡 Daily Spin & Win Wheel APIs
# =========================================================================

SPIN_SEGMENTS = [
    {"id": 0, "type": "try_again", "label": "No Luck ❌", "text": "කණගාටුයි! හෙට නැවත උත්සාහ කරන්න.", "amount": 0.0, "color": "#ef4444", "weight": 35},
    {"id": 1, "type": "wallet_cash", "label": "Rs. 5 Bonus 💰", "text": "සුබ පැතුම්! රු. 5 ක Wallet මුදලක් ලැබුණා!", "amount": 5.0, "color": "#10b981", "weight": 20},
    {"id": 2, "type": "try_again", "label": "Try Tomorrow 🍀", "text": "තව ඩිංගෙන් 100 Diamonds! හෙට නැවත වාසනාව උරගාන්න.", "amount": 0.0, "color": "#f59e0b", "weight": 35},
    {"id": 3, "type": "wallet_cash", "label": "Rs. 2 Bonus 🎁", "text": "සුබ පැතුම්! රු. 2 ක Wallet Bonus මුදලක් ලැබුණා!", "amount": 2.0, "color": "#8b5cf6", "weight": 15},
    {"id": 4, "type": "diamonds_100", "label": "100 Diamonds! 💎", "text": "🔥 JACKPOT! ඔබ 100 Diamonds Grand Prize එක දිනාගත්තා!", "amount": 280.0, "color": "#06b6d4", "weight": 1},
    {"id": 5, "type": "wallet_cash", "label": "Rs. 10 Bonus 💵", "text": "නියමයි! රු. 10 ක Wallet මුදලක් ලැබුණා!", "amount": 10.0, "color": "#10b981", "weight": 5},
    {"id": 6, "type": "try_again", "label": "No Luck Today 🔄", "text": "හොඳ උත්සාහයක්! හෙට නැවත කරකවන්න.", "amount": 0.0, "color": "#64748b", "weight": 25},
    {"id": 7, "type": "diamonds_5", "label": "5 Diamonds 💎", "text": "සුබ පැතුම්! 5 Free Diamonds ලැබුණා!", "amount": 15.0, "color": "#3b82f6", "weight": 3},
]


@app.route("/api/spin/status", methods=["GET", "POST"])
def api_spin_status():
    """Checks if the user can spin the wheel today."""
    user_id = session.get("user_id")
    phone = session.get("user_phone")
    if request.is_json:
        data = request.get_json(silent=True) or {}
        phone = data.get("phone") or phone

    status = can_user_spin(user_id=user_id, phone=phone)
    status["segments"] = [{k: v for k, v in s.items() if k != "weight"} for s in SPIN_SEGMENTS]
    return jsonify(status)


@app.route("/api/spin/play", methods=["POST"])
def api_spin_play():
    """
    Executes a spin using weighted probability.
    Grand prize 100 Diamonds has a strictly controlled low rate.
    """
    import random
    user_id = session.get("user_id")
    phone = session.get("user_phone")

    data = request.get_json(silent=True) or {}
    phone = data.get("phone") or phone
    player_id = data.get("player_id", "")

    # Check eligibility
    eligibility = can_user_spin(user_id=user_id, phone=phone)
    if not eligibility.get("can_spin"):
        return jsonify({"success": False, "message": eligibility.get("message", "ඔබ අද දිනට හිමි Spin එක කරකවා ඇත.")}), 400

    # Weighted random selection
    weights = [s["weight"] for s in SPIN_SEGMENTS]
    selected_segment = random.choices(SPIN_SEGMENTS, weights=weights, k=1)[0]
    winning_index = selected_segment["id"]

    # Record spin in database
    record_spin(
        reward_type=selected_segment["type"],
        reward_label=selected_segment["label"],
        reward_amount=selected_segment["amount"],
        user_id=user_id,
        phone=phone,
    )

    # If won 100 Diamonds Jackpot!
    if selected_segment["type"] == "diamonds_100":
        # Create an admin alert and record winner
        winner_phone = phone or (session.get("user_phone") or "Guest")
        set_setting("latest_jackpot_winner", f"Player: {player_id or 'UID'} | Phone: {winner_phone} | Date: {datetime.now().strftime('%Y-%m-%d %H:%M')}")

    return jsonify({
        "success": True,
        "winning_index": winning_index,
        "reward": {
            "id": selected_segment["id"],
            "type": selected_segment["type"],
            "label": selected_segment["label"],
            "text": selected_segment["text"],
            "amount": selected_segment["amount"],
        },
    })


# =========================================================================
# 👑 Monthly Top-Up Leaderboard API
# =========================================================================

@app.route("/api/leaderboard", methods=["GET"])
def api_leaderboard():
    """Returns top 10 customers/players for the current month."""
    leaderboard = get_monthly_leaderboard()
    
    # Calculate days left in month
    from datetime import date
    import calendar
    today = date.today()
    _, last_day = calendar.monthrange(today.year, today.month)
    days_left = last_day - today.day

    return jsonify({
        "success": True,
        "month_name": today.strftime("%B %Y"),
        "days_left": days_left,
        "leaderboard": leaderboard,
        "prizes": [
            {"rank": 1, "badge": "🥇 1st Place (Grandmaster)", "reward": "Free Weekly Membership 🎟️"},
            {"rank": 2, "badge": "🥈 2nd Place (Master)", "reward": "100 Free Diamonds 💎"},
            {"rank": 3, "badge": "🥉 3rd Place (Diamond King)", "reward": "Rs. 100 Wallet Bonus 💵"},
        ],
    })


# =========================================================================
# 🔔 Live Recent Purchases Notification Ticker API
# =========================================================================

@app.route("/api/recent_purchases", methods=["GET"])
def api_recent_purchases():
    """Returns recent purchases for social proof ticker."""
    real_orders = get_recent_public_purchases(limit=10)
    
    # Seed realistic live gamer pool if database is young
    seed_pool = [
        {"player_name": "Kavindu_FF", "masked_uid": "284****92", "product_name": "100 Diamonds", "amount": 280.0, "time_ago": "තත්පර 15 කට පෙර"},
        {"player_name": "S_U_P_U_N", "masked_uid": "193****44", "product_name": "Weekly Membership", "amount": 350.0, "time_ago": "මීට විනාඩියකට පෙර"},
        {"player_name": "Nipuna_LK", "masked_uid": "302****18", "product_name": "310 Diamonds", "amount": 830.0, "time_ago": "මීට විනාඩි 2 කට පෙර"},
        {"player_name": "CRAZY_Gamer", "masked_uid": "162****80", "product_name": "100 Diamonds", "amount": 280.0, "time_ago": "මීට විනාඩි 3 කට පෙර"},
        {"player_name": "Danushka_99", "masked_uid": "401****63", "product_name": "Weekly Membership", "amount": 350.0, "time_ago": "මීට විනාඩි 4 කට පෙර"},
        {"player_name": "Hasitha_Pro", "masked_uid": "219****77", "product_name": "520 Diamonds", "amount": 1390.0, "time_ago": "මීට විනාඩි 5 කට පෙර"},
    ]

    results = []
    # Add real orders if any
    for r in real_orders:
        results.append({
            "player_name": r["player_name"],
            "masked_uid": r["masked_uid"],
            "product_name": r["product_name"],
            "amount": r["amount"],
            "time_ago": "මීට සුළු මොහොතකට පෙර",
        })

    # Fill remaining from seed pool
    for s in seed_pool:
        if len(results) >= 8:
            break
        results.append(s)

    return jsonify({"success": True, "purchases": results})


# =========================================================================
# 🎰 Mystery Diamond Box System (Guaranteed 80% Win Rate)
# =========================================================================

MYSTERY_BOX_PRICE = 150.0  # Rs. 150 entry

MYSTERY_BOX_ITEMS = [
    # --- WINNING TIER (High Value, Medium & Smaller Prizes) ---
    {
        "id": "win_weekly_vip",
        "type": "weekly_membership",
        "name": "Weekly VIP Membership 👑",
        "diamonds": 0,
        "product_id": "1",
        "value": 350.0,
        "is_win": 1,
        "weight": 8,
        "rarity": "Mythic 👑",
        "color": "#ec4899",
        "desc": "🔥 JACKPOT! රු. 350 ක Weekly VIP Membership දිනාගත්තා!"
    },
    {
        "id": "win_100_diamonds",
        "type": "diamonds_100",
        "name": "100 Free Fire Diamonds 💎",
        "diamonds": 100,
        "product_id": "7",
        "value": 280.0,
        "is_win": 1,
        "weight": 12,
        "rarity": "Legendary 🔥",
        "color": "#00f0ff",
        "desc": "100 Diamonds කෙළින්ම Free Fire Account එකට ලැබුණි!"
    },
    {
        "id": "win_weekly_lite",
        "type": "weekly_lite",
        "name": "Weekly Lite Membership 🌟",
        "diamonds": 0,
        "product_id": "3",
        "value": 120.0,
        "is_win": 1,
        "weight": 15,
        "rarity": "Epic ⚡",
        "color": "#fbbf24",
        "desc": "Weekly Lite Membership එක Account එකට Activate විය!"
    },
    {
        "id": "win_50_diamonds",
        "type": "diamonds_50",
        "name": "50 Free Fire Diamonds 💎",
        "diamonds": 50,
        "product_id": None,
        "value": 140.0,
        "is_win": 1,
        "weight": 15,
        "rarity": "Rare ✨",
        "color": "#a855f7",
        "desc": "50 Diamonds කෙළින්ම Free Fire Account එකට ලැබුණි!"
    },
    {
        "id": "win_25_diamonds",
        "type": "diamonds_25",
        "name": "25 Free Fire Diamonds 💎",
        "diamonds": 25,
        "product_id": "6",
        "value": 75.0,
        "is_win": 1,
        "weight": 18,
        "rarity": "Special ✨",
        "color": "#38bdf8",
        "desc": "25 Diamonds කෙළින්ම Free Fire Account එකට ලැබුණි!"
    },
    {
        "id": "win_10_diamonds",
        "type": "diamonds_10",
        "name": "10 Free Fire Diamonds 💎",
        "diamonds": 10,
        "product_id": None,
        "value": 30.0,
        "is_win": 1,
        "weight": 12,
        "rarity": "Lucky 🍀",
        "color": "#34d399",
        "desc": "10 Diamonds දිනාගත්තා! (රු. 30 ක වටිනාකම Wallet වෙත බැර විය)"
    },
    {
        "id": "win_wallet_100",
        "type": "wallet_cash",
        "name": "Rs. 100 Wallet Cash 💰",
        "diamonds": 0,
        "product_id": None,
        "value": 100.0,
        "is_win": 1,
        "weight": 10,
        "rarity": "Special ✨",
        "color": "#10b981",
        "desc": "රු. 100 ක මුදලක් ඔබගේ SL CAT Wallet එකට බැර විය!"
    },
    {
        "id": "win_wallet_50",
        "type": "wallet_cash",
        "name": "Rs. 50 Wallet Cash 💰",
        "diamonds": 0,
        "product_id": None,
        "value": 50.0,
        "is_win": 1,
        "weight": 15,
        "rarity": "Lucky 🍀",
        "color": "#10b981",
        "desc": "රු. 50 ක මුදලක් ඔබගේ SL CAT Wallet එකට බැර විය!"
    },
    {
        "id": "win_wallet_20",
        "type": "wallet_cash",
        "name": "Rs. 20 Wallet Bonus 🪙",
        "diamonds": 0,
        "product_id": None,
        "value": 20.0,
        "is_win": 1,
        "weight": 12,
        "rarity": "Lucky 🍀",
        "color": "#fbbf24",
        "desc": "රු. 20 ක Bonus මුදලක් Wallet එකට ලැබුණි!"
    },

    # --- NO LUCK TIER (When luck roll fails / 50% Automatic Wallet Refund) ---
    {
        "id": "no_luck_half_refund",
        "type": "no_luck",
        "name": "No Luck (50% Refund) 💔",
        "diamonds": 0,
        "product_id": None,
        "value": 75.0,  # Exactly 50% of Rs. 150 entry fee refunded to wallet
        "is_win": 0,
        "weight": 20,
        "rarity": "No Luck 💔",
        "color": "#94a3b8",
        "desc": "අද වාසනාව මඳි (No Luck)! නමුත් Box ගාස්තුවෙන් 50% ක් (රු. 75.00) ඔබගේ Wallet එකට Instant Refund විය!"
    }
]


MYSTERY_LUCK_TIERS = [
    {"win_rate": 70, "label": "Lucky 🍀", "weight": 15, "color": "#10b981"},
    {"win_rate": 75, "label": "High Luck ⚡", "weight": 25, "color": "#06b6d4"},
    {"win_rate": 80, "label": "Super Lucky 🔥", "weight": 30, "color": "#f59e0b"},
    {"win_rate": 85, "label": "Mega Lucky 🌟", "weight": 18, "color": "#a855f7"},
    {"win_rate": 90, "label": "Mythic Luck 👑", "weight": 9, "color": "#ec4899"},
    {"win_rate": 95, "label": "GODLY LUCK 💎🔥", "weight": 3, "color": "#fbbf24"},
]


@app.route("/api/mystery_box/info", methods=["GET"])
def api_mystery_box_info():
    """Returns mystery box pricing, prize pool with dynamic luck win rate, and recent winners."""
    user_id = session.get("user_id")
    device_id = request.headers.get("X-Device-Id") or request.cookies.get("slcat_device_uuid")
    wallet_bal = get_user_wallet_balance(user_id) if user_id else 0.0

    today_luck = get_user_daily_mystery_luck(user_id, device_id)
    if today_luck:
        luck_info = {
            "has_spun": True,
            "win_rate": int(today_luck["win_rate"]),
            "luck_label": today_luck["luck_label"],
            "can_spin": False,
        }
    else:
        luck_info = {
            "has_spun": False,
            "win_rate": 80,
            "luck_label": "Standard Luck 🍀",
            "can_spin": True,
        }

    return jsonify({
        "success": True,
        "price": MYSTERY_BOX_PRICE,
        "price_formatted": f"Rs. {MYSTERY_BOX_PRICE:.2f}",
        "win_rate": luck_info["win_rate"],
        "today_luck": luck_info,
        "items": MYSTERY_BOX_ITEMS,
        "wallet_balance": wallet_bal,
        "is_logged_in": bool(user_id),
        "recent_winners": get_recent_mystery_box_winners(8),
        "stats": get_mystery_box_stats(),
    })


@app.route("/api/mystery_box/spin_luck", methods=["POST"])
def api_mystery_box_spin_luck():
    """Spins the user's free daily Mystery Box Luck Rate (70% - 95% Win Chance)."""
    import random
    user_id = session.get("user_id")
    data = request.get_json(silent=True) or {}
    device_id = data.get("device_id") or request.headers.get("X-Device-Id") or request.cookies.get("slcat_device_uuid")

    today_luck = get_user_daily_mystery_luck(user_id, device_id)
    if today_luck:
        return jsonify({
            "success": True,
            "already_spun": True,
            "win_rate": int(today_luck["win_rate"]),
            "luck_label": today_luck["luck_label"],
            "message": f"ඔබ අද දිනට හිමි Luck Rate එක ({today_luck['win_rate']}% {today_luck['luck_label']}) දැනටමත් ලබාගෙන ඇත!"
        })

    weights = [t["weight"] for t in MYSTERY_LUCK_TIERS]
    picked = random.choices(MYSTERY_LUCK_TIERS, weights=weights, k=1)[0]

    record_user_daily_mystery_luck(user_id, device_id, picked["win_rate"], picked["label"])

    return jsonify({
        "success": True,
        "already_spun": False,
        "win_rate": picked["win_rate"],
        "luck_label": picked["label"],
        "color": picked.get("color", "#f59e0b"),
        "message": f"🎉 Congratulations! ඔබ අද දින සඳහා {picked['win_rate']}% {picked['label']} Win Rate එකක් දිනාගත්තා!"
    })


@app.route("/api/mystery_box/open", methods=["POST"])
def api_mystery_box_open():
    """Opens a Mystery Box with dynamic winning chance determined by today's luck spin."""
    import random
    user_id = session.get("user_id")
    data = request.get_json(silent=True) or {}
    player_id = str(data.get("player_id", "")).strip()
    nickname = str(data.get("nickname", "Gamer")).strip()
    device_id = data.get("device_id") or request.headers.get("X-Device-Id") or request.cookies.get("slcat_device_uuid")

    if not user_id:
        return jsonify({
            "success": False,
            "require_auth": True,
            "message": "Mystery Box විවෘත කිරීමට කරුණාකර පළමුව ඔබගේ Account එකට Login වන්න (හෝ Wallet Register වන්න)."
        }), 401

    user = get_user_by_id(user_id)
    if not user:
        return jsonify({"success": False, "message": "User not found"}), 404

    # Check Wallet balance for Rs. 150
    current_bal = get_user_wallet_balance(user_id)
    if current_bal < MYSTERY_BOX_PRICE:
        return jsonify({
            "success": False,
            "insufficient": True,
            "balance": current_bal,
            "required": MYSTERY_BOX_PRICE,
            "message": f"ඔබගේ Wallet Balance එක ප්‍රමාණවත් නොවේ (දැනට: Rs. {current_bal:.2f}). Mystery Box සඳහා Rs. {MYSTERY_BOX_PRICE:.2f} ක් අවශ්‍ය වේ. කරුණාකර Deposit කරන්න."
        }), 400

    # 1. Debit Wallet Rs. 150
    order_code = f"MBX-{uuid.uuid4().hex[:8].upper()}"
    debit_res = debit_wallet(user_id, MYSTERY_BOX_PRICE, "Mystery Diamond Box Unboxing", order_code)
    if not debit_res.get("success"):
        return jsonify({"success": False, "message": debit_res.get("message", "Wallet debit failed")}), 400

    # 2. Check today's luck spin for dynamic Win Rate (70% - 95%)
    # 2. Check today's luck spin for dynamic Win Rate (70% - 95%)
    today_luck = get_user_daily_mystery_luck(user_id, device_id)
    active_win_rate = int(today_luck["win_rate"]) if today_luck else 80
    active_luck_label = today_luck["luck_label"] if today_luck else "80% Super Lucky"

    # Roll between 0 and 100 based on active_win_rate:
    # If roll < active_win_rate -> WIN!
    # If roll >= active_win_rate -> NO LUCK!
    roll = random.uniform(0, 100)
    if roll < active_win_rate:
        # Player wins! Choose among winning items (including smaller prizes)
        win_items = [it for it in MYSTERY_BOX_ITEMS if it.get("is_win") == 1]
        win_weights = [float(it.get("weight", 10)) for it in win_items]
        selected_prize = random.choices(win_items, weights=win_weights, k=1)[0]
    else:
        # "no luck කියලා එකකුත් දාන්න ඒකට හැබැයි luck එක නැත්තන් එන්න හදන්න"
        no_luck_item = next((it for it in MYSTERY_BOX_ITEMS if it.get("id") == "no_luck_half_refund"), None)
        if not no_luck_item:
            no_luck_item = {
                "id": "no_luck_half_refund",
                "type": "no_luck",
                "name": "No Luck (50% Refund) 💔",
                "diamonds": 0,
                "product_id": None,
                "value": round(MYSTERY_BOX_PRICE / 2.0, 2),
                "is_win": 0,
                "rarity": "No Luck 💔",
                "color": "#94a3b8",
                "desc": f"අද දින වාසනාව මඳි (No Luck)! නමුත් Box ගාස්තුවෙන් 50% ක් (රු. {MYSTERY_BOX_PRICE / 2.0:.2f}) ඔබගේ Wallet එකට Instant Refund විය!"
            }
        selected_prize = no_luck_item

    delivery_status = "completed"
    delivery_note = ""

    # 3. Fulfill the prize
    if selected_prize["type"] == "no_luck":
        # "සහ ඒකට ආවොත් wallet එකට අදාල ගානෙන් බාගයක් add වෙන්න හදන්න"
        half_refund = round(MYSTERY_BOX_PRICE / 2.0, 2)
        credit_wallet(user_id, half_refund, f"Mystery Box No Luck - 50% Refund (Rs. {half_refund:.2f})", order_code)
        delivery_status = "refunded_50_percent"
        delivery_note = f"No Luck: 50% Refund (Rs. {half_refund:.2f}) ඔබගේ Wallet එකට බැර විය!"
    elif selected_prize["type"] == "wallet_cash":
        credit_wallet(user_id, selected_prize["value"], f"Mystery Box Prize: {selected_prize['name']}", order_code)
        delivery_note = f"Credited Rs. {selected_prize['value']:.2f} to Wallet"
    elif selected_prize.get("product_id") and player_id:
        try:
            from htg_engine import execute_htg_topup
            htg_res = execute_htg_topup(
                player_id=player_id,
                nickname=nickname or "MysteryWinner",
                product_id=selected_prize["product_id"],
                quantity=1
            )
            if htg_res.get("success"):
                delivery_status = "delivered_htg"
                delivery_note = f"Delivered via HTG: {', '.join(htg_res.get('order_ids', []))}"
            else:
                credit_wallet(user_id, selected_prize["value"], f"Mystery Box Prize Value Refund: {selected_prize['name']}", order_code)
                delivery_status = "credited_to_wallet"
                delivery_note = "HTG API - Value credited to wallet!"
        except Exception:
            credit_wallet(user_id, selected_prize["value"], f"Mystery Box Prize Value: {selected_prize['name']}", order_code)
            delivery_status = "credited_to_wallet"
            delivery_note = "Value credited to wallet"
    else:
        credit_wallet(user_id, selected_prize["value"], f"Mystery Box Prize: {selected_prize['name']}", order_code)
        delivery_status = "credited_to_wallet"
        delivery_note = f"Credited value (Rs. {selected_prize['value']:.2f}) to Wallet"

    # 4. Record to Database
    record_mystery_box_open(
        user_id=user_id,
        player_id=player_id or "N/A",
        nickname=nickname or user["name"],
        order_code=order_code,
        amount_paid=MYSTERY_BOX_PRICE,
        won_item_id=selected_prize["id"],
        won_item_name=selected_prize["name"],
        won_item_type=selected_prize["type"],
        won_amount=selected_prize["value"],
        is_win=selected_prize["is_win"],
        delivery_status=delivery_status
    )

    new_wallet_balance = get_user_wallet_balance(user_id)

    return jsonify({
        "success": True,
        "order_code": order_code,
        "prize": selected_prize,
        "win_rate_used": active_win_rate,
        "luck_label": active_luck_label,
        "new_balance": new_wallet_balance,
        "new_balance_formatted": f"Rs. {new_wallet_balance:.2f}",
        "delivery_note": delivery_note,
        "delivery_status": delivery_status
    })


# =========================================================================
# 📦 Animated Live Delivery Tracker (Domino's Pizza Tracker) API
# =========================================================================

@app.route("/api/order/timeline/<order_code>", methods=["GET"])
def api_order_timeline(order_code):
    """Returns real-time 4-step delivery progression timeline for an order."""
    code = str(order_code).strip().upper()
    order = get_order(code)
    if not order:
        return jsonify({"success": False, "message": f"Order code '{code}' හමු නොවීය."}), 404

    status = order.get("status", "pending_payment")
    is_completed = status == "completed"
    is_processing = status in ("payment_submitted", "awaiting_bank_confirmation", "processing")
    is_rejected = status in ("rejected", "failed")

    steps = [
        {
            "step": 1,
            "title": "Payment Confirmed",
            "title_si": "ගෙවීම ලැබී තහවුරු විය",
            "desc": "LankaQR / Wallet transaction verified",
            "status": "completed" if (is_completed or is_processing) else "active",
            "icon": "💰"
        },
        {
            "step": 2,
            "title": "Player UID & Nickname Verified",
            "title_si": "Free Fire Player UID තහවුරු කිරීම",
            "desc": f"UID: {order.get('player_id', '')} ({order.get('nickname') or 'Player'})",
            "status": "completed" if (is_completed or is_processing) else "pending",
            "icon": "🛡️"
        },
        {
            "step": 3,
            "title": "Connecting Garena Server (HTG)",
            "title_si": "Garena Official Server සමඟ සම්බන්ධ වීම",
            "desc": "Instant high-speed API handshake established",
            "status": "completed" if is_completed else ("active" if is_processing else "pending"),
            "icon": "⚡"
        },
        {
            "step": 4,
            "title": "Diamonds Injected to Game",
            "title_si": "Diamonds සාර්ථකව Account එකට ලැබුණි",
            "desc": f"Delivery Ref: {order.get('htg_order_ids') or 'Auto-Delivery Complete'}",
            "status": "completed" if is_completed else "pending",
            "icon": "💎"
        }
    ]

    return jsonify({
        "success": True,
        "order_code": code,
        "product_name": order.get("product_name"),
        "amount": order.get("amount"),
        "amount_formatted": f"Rs. {order.get('amount', 0):,.2f}",
        "player_id": order.get("player_id"),
        "nickname": order.get("nickname") or "Player",
        "status": status,
        "is_completed": is_completed,
        "is_rejected": is_rejected,
        "created_at": order.get("created_at"),
        "updated_at": order.get("updated_at"),
        "htg_order_ids": order.get("htg_order_ids"),
        "slip_path": order.get("slip_path"),
        "has_slip": bool(order.get("slip_path")),
        "can_upload_slip": not bool(order.get("slip_path")) and not is_completed,
        "steps": steps,
        "progress_percent": 100 if is_completed else (66 if is_processing else 25)
    })


# =========================================================================
# 🧾 Digital Receipt Generator API
# =========================================================================

@app.route("/api/receipt/<order_code>", methods=["GET"])
def api_get_receipt(order_code):
    """Returns complete digital receipt information for an order."""
    order = get_order(order_code)
    if not order:
        return jsonify({"success": False, "message": "Order එක සොයාගත නොහැක."}), 404

    receipt = {
        "order_code": order["order_code"],
        "player_id": order["player_id"],
        "nickname": order.get("nickname") or "Free Fire Player",
        "product_name": order["product_name"],
        "amount": order["amount"],
        "amount_formatted": f"Rs. {order['amount']:,.2f}",
        "status": order["status"],
        "payment_method": "Dynamic LankaQR (Seylan HelaPOS)",
        "created_at": order["created_at"],
        "tx_reference": order.get("tx_reference") or f"LQR-{order['order_code']}",
        "store_name": "SL CAT TOPUP CENTER",
        "store_contact": "+63 910 456 8696",
        "verified": order["status"] == "completed",
    }
    return jsonify({"success": True, "receipt": receipt})


# =========================================================================
# 🚨 Low Server Delivery Balance WhatsApp Alert Engine
# =========================================================================

def check_and_trigger_low_balance_alert(force: bool = False) -> Dict[str, Any]:
    """
    Monitors live server delivery stock balance.
    If balance drops below threshold, triggers an urgent alert with direct WhatsApp trigger,
    and if CallMeBot key is configured, dispatches an automated WhatsApp push message.
    Includes 30-minute cooldown to prevent spamming the admin.
    """
    try:
        from htg_stock_manager import get_htg_accounts_balance_summary
        summary = get_htg_accounts_balance_summary()
        current_bal = float(summary.get("effective_combined_balance", summary.get("active_balance", 0.0)) or 0.0)
    except Exception:
        balance_info = check_htg_balance()
        current_bal = float(balance_info.get("balance", 0.0) or 0.0)

    try:
        threshold = float(get_setting("low_balance_threshold", "3000.0") or 3000.0)
    except Exception:
        threshold = 3000.0

    admin_phone = get_setting("admin_whatsapp_phone", "639104568696") or "639104568696"
    callmebot_key = get_setting("callmebot_api_key", "").strip()

    is_low = current_bal < threshold

    now_ts = int(time.time())
    try:
        last_alert_ts = int(float(get_setting("last_low_balance_alert_ts", "0") or 0))
    except Exception:
        last_alert_ts = 0
    cooldown_seconds = 1800  # 30 minutes cooldown

    should_dispatch = False
    if is_low:
        if force or (now_ts - last_alert_ts >= cooldown_seconds):
            should_dispatch = True
            set_setting("last_low_balance_alert_ts", str(now_ts))
    else:
        # If balance recovered above threshold, reset cooldown flag
        if last_alert_ts > 0:
            set_setting("last_low_balance_alert_ts", "0")

    now_str = datetime.now().strftime("%Y-%m-%d %I:%M %p")
    wa_alert_text = (
        f"🚨 *SL CAT TOPUP - SERVER BALANCE ALERT* 🚨\n"
        f"━━━━━━━━━━━━━━━━━━━━━\n"
        f"⚠️ *සජීවී Delivery Balance එක අඩු වී ඇත!*\n"
        f"💰 *වත්මන් ශේෂය:* Rs. {current_bal:,.2f}\n"
        f"📉 *අවම සීමාව (Threshold):* Rs. {threshold:,.2f}\n"
        f"⏰ *වේලාව:* {now_str}\n"
        f"━━━━━━━━━━━━━━━━━━━━━\n"
        f"🛒 පාරිභෝගිකයින්ගේ ඇණවුම් Out of Stock වීම වැළැක්වීමට කරුණාකර දැන්ම Wallet එක Recharge කරන්න."
    )
    encoded_text = urllib.parse.quote(wa_alert_text)
    wa_url = f"https://wa.me/{admin_phone}?text={encoded_text}"

    # If should_dispatch and callmebot_key is configured, send autonomous WhatsApp push
    if should_dispatch and callmebot_key:
        def _send_wa():
            try:
                cb_url = f"https://api.callmebot.com/whatsapp.php?phone={admin_phone}&text={encoded_text}&apikey={callmebot_key}"
                requests.get(cb_url, timeout=10)
                logger.info(f"Dispatched autonomous WhatsApp low balance alert to {admin_phone}")
            except Exception as ex:
                logger.warning(f"Could not dispatch CallMeBot alert: {ex}")
        threading.Thread(target=_send_wa, daemon=True).start()

    return {
        "is_low": is_low,
        "dispatched": should_dispatch,
        "current_balance": current_bal,
        "current_balance_formatted": f"Rs. {current_bal:,.2f}",
        "threshold": threshold,
        "threshold_formatted": f"Rs. {threshold:,.2f}",
        "admin_phone": admin_phone,
        "whatsapp_url": wa_url,
        "message": wa_alert_text,
    }


@app.route("/api/admin/htg/low_balance_status", methods=["GET"])
@app.route("/api/admin/low_balance_status", methods=["GET"])
def api_htg_low_balance_status():
    """Checks account balance and flags low balance alert."""
    admin_auth = session.get("is_admin")
    if not admin_auth:
        return jsonify({"success": False, "message": "Unauthorized"}), 401

    res = check_and_trigger_low_balance_alert()
    return jsonify({
        "success": True,
        "is_low": res["is_low"],
        "balance": res["current_balance"],
        "threshold": res["threshold"],
        "whatsapp_alert_url": res["whatsapp_url"],
        "message": res["message"],
    })



@app.route("/order/<order_code>")
def order_view(order_code):
    """Customer order tracking page."""
    order = get_order(order_code)
    if not order:
        return "Order not found", 404

    qr_base64 = None
    if order.get("qr_payload"):
        qr_base64 = generate_qr_base64(order["qr_payload"])

    return render_template("order_status.html", order=order, qr_base64=qr_base64)


@app.route("/api/order_status/<order_code>")
def api_order_status(order_code):
    """Real-time status check for polling."""
    order = get_order(order_code)
    if not order:
        return jsonify({"success": False, "message": "Order not found"}), 404

    # Auto-reject check: If order has been in pending_payment for > 5 minutes, auto-reject immediately!
    if order["status"] == "pending_payment":
        order_time_str = order.get("created_at")
        if order_time_str:
            try:
                ot = datetime.strptime(order_time_str, "%Y-%m-%d %H:%M:%S")
                if (datetime.now() - ot).total_seconds() > 900:
                    reject_order(order_code, reason="ගෙවීම් කාලය (මිනිත්තු 15) ඉකුත් විය (Auto-rejected: 15-minute payment window expired)")
                    order = get_order(order_code)
                    return jsonify({"success": True, "order": order})
            except Exception:
                pass

    # If order is waiting for payment confirmation, check if bank alert arrived
    if order["status"] in ["pending_payment", "payment_submitted"]:
        ref = order.get("tx_reference")
        # Ensure we only check for notifications that arrived around or after order creation!
        # 30 seconds buffer for clock variation between phone and server
        order_time_str = order.get("created_at")
        min_notif_time = None
        if order_time_str:
            try:
                ot = datetime.strptime(order_time_str, "%Y-%m-%d %H:%M:%S")
                min_notif_time = (ot - timedelta(seconds=30)).strftime("%Y-%m-%d %H:%M:%S")
            except Exception:
                min_notif_time = None

        matching_notif = None
        if ref:
            matching_notif = find_matching_notification(
                order["amount"], 
                reference=ref, 
                require_reference=True, 
                max_age_minutes=15, 
                min_timestamp=min_notif_time
            )
        if not matching_notif:
            # SECURITY: allow_lankaqr_only_without_ref=True ensures personal ePassbook/SMS payments never match!
            matching_notif = find_matching_notification(
                order["amount"], 
                require_reference=False, 
                max_age_minutes=15, 
                min_timestamp=min_notif_time,
                allow_lankaqr_only_without_ref=True
            )

        if matching_notif:
            mark_notification_matched(matching_notif["id"], order_code)
            if not ref and matching_notif.get("reference"):
                update_order_payment(order_code, tx_reference=matching_notif["reference"])
            process_and_deliver_order(order_code)
            order = get_order(order_code)

    # Real-time HTG Queue Verification for processing orders
    if order and order.get("status") == "processing" and order.get("htg_order_ids"):
        htg_id = str(order["htg_order_ids"]).split(" ")[0].split("(")[0].strip()
        if htg_id.startswith(("LVL-", "MY-", "ODR-")):
            try:
                from htg_engine import check_htg_order_queue
                htg_item = check_htg_order_queue(order_id=htg_id, player_id=order["player_id"])
                if htg_item:
                    qst = str(htg_item.get("queue_status", "")).strip().lower()
                    hst = str(htg_item.get("status", "")).strip().lower()
                    res_id = str(htg_item.get("result_id", ""))
                    if qst == "done" or hst in ["success", "completed", "done"]:
                        full_id = f"{htg_id} (Ref: {res_id})" if res_id and res_id != "-" else htg_id
                        mark_order_completed(order_code, full_id)
                        order = get_order(order_code)
                    elif qst in ["failed", "cancel", "rejected"] or hst in ["failed", "refund", "invalid product", "cancel", "cancelled"]:
                        fail_msg = f"HTG/Garena queue rejected order ({htg_id}). Free Fire UID {order['player_id']} ineligible, already purchased Level Up Pass, or region mismatch."
                        refund_failed_order(order_code, fail_msg)
                        order = get_order(order_code)
            except Exception as e:
                logger.warning(f"Error checking HTG queue in api_order_status: {e}")

    return jsonify({"success": True, "order": order})


# =====================================================================
# AUTOMATED ORDER PROCESSING & DELIVERY PIPELINE
# =====================================================================

def process_and_deliver_order(order_code: str, force: bool = False, account_key: Optional[str] = None) -> dict:
    """
    Executes automated fulfillment for a paid order on HTG Digital.
    Deducts from owner's HTG credits and credits client's Free Fire UID.
    Optionally targets specific HTG account (account_1 or account_2).
    """
    order = get_order(order_code)
    if not order:
        return {"success": False, "message": "Order not found"}

    if order["status"] == "completed":
        return {"success": True, "message": "Order already completed", "order": order}

    # Atomically claim order to prevent race condition / duplicate crediting / double HTG delivery
    claimed = mark_order_processing(order_code, force=force)
    if not claimed:
        fresh_order = get_order(order_code)
        if fresh_order and fresh_order["status"] == "completed":
            return {"success": True, "message": "Order already completed", "order": fresh_order}
        return {"success": False, "message": f"Order cannot be delivered (Current status: {fresh_order.get('status', 'unknown') if fresh_order else 'unknown'})"}

    # Check if this order is a wallet deposit
    if order.get("product_id") == "wallet_deposit":
        user_id = order.get("user_id")
        if user_id:
            credit_res = credit_wallet(user_id, order["amount"], "LankaQR Wallet Deposit", order_code)
            mark_order_completed(order_code, f"WALLET-CREDIT-OK (Rs. {order['amount']:.2f})")
            return {
                "success": True,
                "message": f"Wallet credited with Rs. {order['amount']:.2f}!",
                "order_ids": "WALLET-CREDIT-OK",
                "new_balance": credit_res.get("new_balance"),
            }
        else:
            mark_order_failed(order_code, "User ID not linked to wallet deposit")
            return {"success": False, "message": "User not linked"}

    # Check if this order contains multiple items (cart order)
    cart_items = []
    try:
        if order.get("items_json"):
            cart_items = json.loads(order["items_json"])
    except Exception:
        cart_items = []

    if cart_items and isinstance(cart_items, list) and len(cart_items) > 0:
        all_oids = []
        failed_items = []
        any_pending = False
        for itm in cart_items:
            sub_pid = str(itm.get("product_id") or itm.get("id") or "").strip()
            sub_qty = max(1, int(itm.get("quantity") or itm.get("qty") or 1))
            sub_res = execute_htg_topup(
                player_id=order["player_id"],
                nickname=order.get("nickname") or "Customer",
                product_id=sub_pid,
                quantity=sub_qty,
                preferred_account=account_key,
            )
            if sub_res.get("success"):
                all_oids.extend(sub_res.get("order_ids", []))
                if sub_res.get("pending_queue"):
                    any_pending = True
            else:
                failed_items.append({"item": itm, "error": sub_res.get("message", "HTG delivery failed")})

        oids_str = ", ".join(all_oids) or "HTG-MULTI-SUCCESS"
        if not failed_items:
            if any_pending:
                mark_order_processing(order_code, force=True)
                with get_connection() as conn:
                    cursor = conn.cursor()
                    cursor.execute("UPDATE orders SET htg_order_ids = ?, error_message = NULL WHERE order_code = ?", (oids_str, order_code))
                    conn.commit()
                return {
                    "success": True,
                    "message": f"Order {order_code} ({len(cart_items)} items) queued ({oids_str}). Checking delivery...",
                    "order_ids": oids_str,
                    "status": "processing",
                }
            else:
                mark_order_completed(order_code, oids_str)
                threading.Thread(target=check_and_trigger_low_balance_alert, daemon=True).start()
                return {
                    "success": True,
                    "message": f"Order {order_code} successfully delivered all {len(cart_items)} items (ID: {oids_str})",
                    "order_ids": oids_str,
                    "status": "completed",
                }
        else:
            err_msg = f"Failed to deliver {len(failed_items)} of {len(cart_items)} items on server: {failed_items[0].get('error')}"
            mark_order_failed(order_code, err_msg)
            if oids_str:
                with get_connection() as conn:
                    cursor = conn.cursor()
                    cursor.execute("UPDATE orders SET htg_order_ids = ? WHERE order_code = ?", (oids_str, order_code))
                    conn.commit()
            ref_res = refund_failed_order(order_code, err_msg)
            return {
                "success": False,
                "message": err_msg,
                "order_ids": oids_str,
                "refunded": ref_res.get("refunded", False),
                "status": "failed",
            }

    # Deliver via Server Direct (Single product)
    res = execute_htg_topup(
        player_id=order["player_id"],
        nickname=order.get("nickname") or "Customer",
        product_id=order["product_id"],
        quantity=order.get("quantity", 1),
        preferred_account=account_key,
    )

    if res.get("success"):
        oids = ", ".join(res.get("order_ids", [])) or "DELIVERY-SUCCESS"
        if res.get("pending_queue"):
            mark_order_processing(order_code, force=True)
            with get_connection() as conn:
                cursor = conn.cursor()
                cursor.execute("UPDATE orders SET htg_order_ids = ?, error_message = NULL WHERE order_code = ?", (oids, order_code))
                conn.commit()
            return {
                "success": True,
                "message": f"Order {order_code} queued ({oids}). Checking delivery...",
                "order_ids": oids,
                "status": "processing",
            }
        else:
            mark_order_completed(order_code, oids)
            threading.Thread(target=check_and_trigger_low_balance_alert, daemon=True).start()
            return {
                "success": True,
                "message": f"Order {order_code} successfully delivered (ID: {oids})",
                "order_ids": oids,
                "status": "completed",
            }
    else:
        err = res.get("message", "Topup execution failed")
        mark_order_failed(order_code, err)
        fail_oid = res.get("order_id")
        if fail_oid:
            with get_connection() as conn:
                cursor = conn.cursor()
                cursor.execute("UPDATE orders SET htg_order_ids = ? WHERE order_code = ?", (fail_oid, order_code))
                conn.commit()

        # 100% AUTOMATIC REFUND FOR FAILED HTG ORDERS
        ref_res = refund_failed_order(order_code, err)
        if ref_res.get("refunded"):
            logger.info(f"Auto-refunded Rs. {order['amount']} for failed order {order_code} to user {ref_res.get('user_id')}")

        return {
            "success": False,
            "message": f"Delivery failed: {err}",
            "refunded": ref_res.get("refunded", False),
        }


# =====================================================================
# AUTOMATED PAYMENT NOTIFICATION & WEBHOOKS
# =====================================================================

@app.route("/api/payment/lankaqr_callback", methods=["POST"])
def api_lankaqr_callback():
    """
    Direct Webhook for HelaPOS / Bank LankaQR payment notifications.
    Accepts JSON: {order_code, amount, status: 'SUCCESS', reference}
    """
    data = request.get_json(silent=True) or request.form.to_dict() or {}
    status = str(data.get("status", "")).upper()
    order_code = data.get("order_code")
    amount = float(data.get("amount", 0.0)) if data.get("amount") else None
    ref = data.get("reference") or data.get("tx_id")

    if status in ["SUCCESS", "PAID", "COMPLETED", "APPROVED"]:
        order = None
        if order_code:
            order = get_order(order_code)
        elif amount:
            order = find_pending_order_by_amount(amount, reference=ref)

        if order:
            update_order_payment(order["order_code"], tx_reference=ref)
            res = process_and_deliver_order(order["order_code"])
            return jsonify({
                "success": True,
                "message": "Payment verified and order fulfilled automatically!",
                "delivery": res,
            })

    return jsonify({"success": False, "message": "Ignored or invalid status"}), 400


@app.route("/api/verify_reference", methods=["POST"])
def api_verify_reference():
    """
    Advanced verification when customer enters their Bank Transaction / Reference ID.
    Strictly checks against incoming bank notifications (Email, SMS, Webhook).
    ONLY fulfills and marks completed IF the reference ID is verified by bank alert!
    """
    data = request.get_json(silent=True) or request.form.to_dict() or {}
    order_code = data.get("order_code")
    reference_id = str(data.get("reference_id", "")).strip()

    if not order_code or not reference_id:
        return jsonify({"success": False, "message": "කරුණාකර නිවැරදි Reference / Payment ID එකක් ඇතුළත් කරන්න."}), 400

    order = get_order(order_code)
    if not order:
        return jsonify({"success": False, "message": "Order එක සොයාගත නොහැකි විය."}), 404

    if order["status"] == "completed":
        return jsonify({
            "success": True,
            "status": "completed",
            "message": "මෙම ඇණවුම දැනටමත් සාර්ථකව Deliver කර ඇත (Already Completed)!",
        })

    clean_ref = "".join(c for c in reference_id if c.isalnum())
    if len(clean_ref) < 6:
        return jsonify({
            "success": False,
            "status": "invalid_reference",
            "message": "කරුණාකර වලංගු Bank Reference / Transaction ID එකක් ඇතුළත් කරන්න (අවම වශයෙන් අංක/අකුරු 6ක්).",
        }), 400

    # Check for duplicate reference across orders
    is_dup_ref, dup_ref_msg, dup_ref_order, dup_ref_type = check_duplicate_slip(tx_reference=reference_id, exclude_order_code=order_code)
    if is_dup_ref:
        orig_ref_code = dup_ref_order.get("order_code") if dup_ref_order else ""
        if dup_ref_type == "pending_reorder":
            with get_connection() as conn:
                cursor = conn.cursor()
                cursor.execute(
                    "UPDATE orders SET status = 'cancelled', error_message = ? WHERE order_code = ?",
                    (f"ස්වයංක්‍රීයව අවලංගු විය: පෙර ඇණවුමේ ({orig_ref_code}) Reference අනුපිටපතකි", order_code),
                )
                conn.commit()
            return jsonify({
                "success": False,
                "is_duplicate_reorder": True,
                "original_order_code": orig_ref_code,
                "message": dup_ref_msg,
                "redirect_url": f"/order/{orig_ref_code}",
            }), 200
        else:
            return jsonify({
                "success": False,
                "security_blocked": True,
                "is_already_completed": True,
                "original_order_code": orig_ref_code,
                "message": f"🚨 ආරක්ෂක පද්ධතිය මඟින් ප්‍රතික්ෂේප විය:\n{dup_ref_msg}",
            }), 400

    # Save reference on order and mark status as payment_submitted
    update_order_payment(order_code, tx_reference=reference_id)

    # 1. Strictly check if a bank notification matching this reference has arrived
    matching_notif = find_matching_notification(order["amount"], reference=reference_id, require_reference=True)
    if matching_notif:
        mark_notification_matched(matching_notif["id"], order_code)
        res = process_and_deliver_order(order_code)
        if res.get("success"):
            return jsonify({
                "success": True,
                "status": "completed",
                "message": "Reference ID එක බැංකු වාර්තා සමඟ සාර්ථකව තහවුරු විය! Top-Up සාර්ථකව Deliver කරන ලදී!",
                "delivery": res,
            })
        else:
            return jsonify({
                "success": False,
                "status": "delivery_failed",
                "message": f"බැංකු ගෙවීම තහවුරුයි, නමුත් Delivery දෝෂයකි: {res.get('message', 'Insufficient server balance')}",
                "delivery": res,
            })

    # 2. If NO matching bank notification has arrived yet:
    # DO NOT auto-deliver! Free diamonds are NOT given out for unverified references.
    return jsonify({
        "success": True,
        "status": "awaiting_bank_confirmation",
        "message": "Reference ID එක ලැබුණි. බැංකු පද්ධතියෙන් (Email/SMS) මුදල් ලැබී ඇති බව තහවුරු වන තුරු රැඳී සිටින්න...",
    })



@app.route("/api/helapos_notify", methods=["POST", "GET"])
@app.route("/api/pos_alert", methods=["POST", "GET"])
@app.route("/api/payment/sms_webhook", methods=["POST", "GET"])
def api_sms_webhook():
    """
    Automated SMS / Notification Forwarder Webhook.
    Receives incoming SMS from Seylan Bank / HelaPOS notifications from Android app.
    100% crash-proof and safe across all CGI/WSGI environments.
    """
    import re

    try:
        data = None
        try:
            data = request.get_json(silent=True)
        except Exception:
            data = None

        if not data and request.form:
            try:
                data = request.form.to_dict()
            except Exception:
                data = None

        if not data:
            data = {}

        raw_payload = ""
        try:
            raw_payload = request.get_data(as_text=True) or ""
        except Exception:
            raw_payload = ""

        message_text = (
            data.get("message")
            or data.get("text")
            or data.get("content")
            or data.get("body")
            or data.get("notification")
            or data.get("msg")
            or request.args.get("message")
            or raw_payload
            or ""
        )
        sender = data.get("sender") or data.get("from") or data.get("title") or request.args.get("sender") or "HelaPOS"

        # Search for amount in message_text or raw_payload (Sinhala රු / රු. and English Rs. / LKR)
        search_text = f"{message_text} {raw_payload}"

        # 1. Ignore merchant outgoing debits
        if re.search(r"\bdebit\s+for\b|\bdebited\b", search_text, re.IGNORECASE):
            return jsonify({
                "success": True,
                "status": "ignored",
                "message": "Debit transaction ignored (Owner outgoing payment)."
            }), 200

        # 2. Extract amount - supports ePassbook "Credit for LKR 75.00 to AC No.*****85799", HelaPOS, Seylan, etc.
        amt_match = re.search(r"(?:Credit|credited|Payment|received)?\s*(?:for|of|with)?\s*(?:රු\.?|LKR|Rs\.?)\s*([\d,]+(?:\.\d+)?)", search_text, re.IGNORECASE)
        if not amt_match:
            amt_match = re.search(r"(?:රු\.?|LKR|Rs\.?|Payment\s+(?:of\s+)?|credited\s+(?:with\s+)?|Amount:?)\s*([\d,]+(?:\.\d+)?)", search_text, re.IGNORECASE)
        if not amt_match:
            amt_match = re.search(r"([\d,]+(?:\.\d+)?)\s*(?:රු\.?|LKR|Rs\.?)", search_text, re.IGNORECASE)
        if not amt_match:
            amt_match = re.search(r"\b(\d{2,6}\.\d{2})\b", search_text)
        if not amt_match:
            # Fallback for known Free Fire package amounts in our store
            amt_match = re.search(r"\b(75|140|280|350|520|840|1000|1050|1390|2100|2450|3455|4000|5000)\b", search_text)

        # Extract Reference ID
        ref_code = data.get("reference") or data.get("tx_id")
        if not ref_code:
            ref_match = re.search(r"\b(\d{10,14})\b", search_text)
            if ref_match:
                ref_code = ref_match.group(1)
            else:
                cat_match = re.search(r"(CAT-[A-Z0-9]{8})", search_text, re.IGNORECASE)
                if cat_match:
                    ref_code = cat_match.group(1)

        if amt_match:
            try:
                amt = float(amt_match.group(1).replace(",", ""))
                # 1. Record bank notification in DB (with strict 2-hour deduplication)
                notif_id = record_bank_notification(
                    source=f"SMS_{sender}",
                    amount=amt,
                    reference=ref_code,
                    raw_text=message_text[:500]
                )

                if not notif_id:
                    # Duplicate alert already processed previously! Reject immediately!
                    return jsonify({
                        "success": True,
                        "status": "duplicate_ignored",
                        "message": "Duplicate payment alert already processed. Ignored to prevent duplicate fulfillment."
                    }), 200

                # 2. Check if an order is already waiting for this reference
                order = None
                if ref_code:
                    clean_ref = "".join(c for c in ref_code if c.isalnum())
                    with get_connection() as conn:
                        cur = conn.cursor()
                        cur.execute(
                            "SELECT * FROM orders WHERE tx_reference LIKE ? AND status IN ('pending_payment', 'payment_submitted') ORDER BY id DESC LIMIT 1",
                            (f"%{clean_ref}%",)
                        )
                        r = cur.fetchone()
                        if r:
                            order = dict(r)

                # 3. Security: Distinguish genuine LankaQR alerts vs personal bank transfers (ePassbook, etc.)
                is_lankaqr_alert = bool(
                    re.search(r"LankaQR|HelaPOS|Seylan", search_text, re.IGNORECASE)
                    or "HelaPOS" in str(sender)
                    or "Seylan" in str(sender)
                )

                if not order:
                    if is_lankaqr_alert:
                        # Genuine LankaQR payment via Seylan HelaPOS Terminal
                        order = find_pending_order_by_amount(amt, reference=ref_code, max_age_minutes=15)
                    else:
                        # Direct bank transfer (Commercial Bank ePassbook, etc.)
                        # Check if amount has unique random cents (10 to 99)
                        cents = round((amt - int(amt)) * 100)
                        if 10 <= cents <= 99:
                            # UNIQUE CENTS MATCH: 100% mathematically guaranteed to be our store order!
                            order = find_pending_order_by_amount(amt, reference=ref_code, max_age_minutes=15)
                            if order:
                                print(f"🎯 [AUTO-MATCH] Unique cents matched ePassbook order {order['order_code']} (LKR {amt:.2f})!")
                        else:
                            # Round figure (e.g. .00) - Personal deposit to merchant account!
                            print(f"🛡️ [SECURITY] Round-figure personal transfer recorded (LKR {amt:.2f} from {sender}). Auto-matching skipped without reference to protect merchant personal funds.")

                if order:
                    if order.get("status") == "completed":
                        return jsonify({
                            "success": True,
                            "matched_order": order["order_code"],
                            "message": "Order already completed",
                        }), 200
                    mark_notification_matched(notif_id, order["order_code"])
                    update_order_payment(order["order_code"], tx_reference=ref_code or sender)
                    res = process_and_deliver_order(order["order_code"])
                    return jsonify({
                        "success": True,
                        "matched_order": order["order_code"],
                        "delivery": res,
                    }), 200
                else:
                    return jsonify({
                        "success": True,
                        "message": "Bank alert recorded safely. Awaiting customer reference or admin approval.",
                        "notification_id": notif_id
                    }), 200
            except Exception as e:
                return jsonify({"success": False, "error": str(e)}), 200

        # If test ping or no amount pattern matched:
        return jsonify({
            "success": True,
            "status": "connected",
            "message": "HelaPOS Webhook connection verified successfully! Send real notification to parse amount.",
            "received_preview": message_text[:120]
        }), 200
    except Exception as e:
        return jsonify({"success": False, "error": str(e)}), 200



@app.route("/api/admin/record_bank_alert", methods=["POST"])
def api_admin_record_bank_alert():
    """Admin endpoint to manually record/verify a bank alert."""
    pin = request.headers.get("X-Admin-PIN") or (request.json and request.json.get("pin"))
    if pin != ADMIN_PIN and not session.get("admin_logged_in"):
        return jsonify({"success": False, "message": "Unauthorized"}), 403

    data = request.get_json(silent=True) or {}
    amt = float(data.get("amount", 0.0))
    ref = str(data.get("reference", "")).strip()

    if amt <= 0 or not ref:
        return jsonify({"success": False, "message": "Amount and Reference required"}), 400

    notif_id = record_bank_notification(
        source="Admin Manual / Bank Verified",
        amount=amt,
        reference=ref,
        raw_text=f"Manually recorded bank payment of Rs. {amt:.2f} Ref: {ref}"
    )
    return jsonify({"success": True, "message": f"Bank Alert for Rs. {amt:.2f} (Ref: {ref}) recorded!", "notification_id": notif_id})



@app.route("/api/payment/simulate_paid/<order_code>", methods=["POST", "GET"])
def api_simulate_paid(order_code):
    """
    Simulation endpoint for testing the instant QR Scan Success & Auto-Delivery on localhost.
    Instantly marks order as paid and delivers diamonds/memberships on HTG Digital!
    """
    order = get_order(order_code)
    if not order:
        return jsonify({"success": False, "message": "Order not found"}), 404

    update_order_payment(order_code, tx_reference=f"LANKAQR-SCAN-OK-{int(time.time())}")
    res = process_and_deliver_order(order_code)
    return jsonify({
        "success": True,
        "message": "Payment detected and Auto-Delivery executed!",
        "result": res,
    })


# =====================================================================
# ADMIN DASHBOARD ROUTES
# =====================================================================

@app.route("/admin", methods=["GET", "POST"])
def admin_dashboard():
    """Admin portal to view orders and trigger fulfillment."""
    admin_profile = {
        "display_name": get_setting("admin_display_name", "Crazy Owner"),
        "avatar": get_setting("admin_avatar", "👑"),
        "phone": get_setting("admin_whatsapp_phone", "639104568696"),
        "ff_id": get_setting("admin_ff_id", ADMIN_FF_ID),
    }

    current_pin = get_setting("admin_pin", ADMIN_PIN)

    # Check remember-me token cookie
    rem_token = request.cookies.get("slcat_admin_token")
    if rem_token and rem_token == get_setting("admin_remember_token", ""):
        session["admin_logged"] = True

    if request.method == "POST":
        pin = request.form.get("admin_pin", "")
        remember = bool(request.form.get("remember_me"))
        if not pin and request.is_json:
            jdata = request.get_json(silent=True) or {}
            pin = jdata.get("admin_pin", "")
            remember = bool(jdata.get("remember_me"))

        if pin == current_pin:
            session["admin_logged"] = True
            token_val = None
            if remember:
                session.permanent = True
                token_val = f"adm_{uuid.uuid4().hex}"
                set_setting("admin_remember_token", token_val)

            if request.is_json:
                resp = jsonify({"success": True, "redirect": "/admin"})
            else:
                resp = redirect(url_for("admin_dashboard"))

            if token_val:
                resp.set_cookie("slcat_admin_token", token_val, max_age=30*24*3600, httponly=True, samesite="Lax")
            return resp
        else:
            if request.is_json:
                return jsonify({"success": False, "message": "වැරදි Admin PIN එකක්! කරුණාකර නැවත උත්සාහ කරන්න."}), 401
            return render_template("admin.html", error="වැරදි Admin PIN එකක්!", logged=False, rating_stats={}, admin_profile=admin_profile)

    if not session.get("admin_logged"):
        return render_template("admin.html", logged=False, rating_stats={}, admin_profile=admin_profile)

    orders = get_all_orders(limit=250)
    users = get_all_users_with_wallets(limit=100)
    stats = get_admin_stats()
    htg_info = check_htg_balance()
    htg_accounts = get_all_htg_accounts_status()

    banned_devices = get_banned_devices()
    rating_stats = get_chat_rating_stats()
    coupons = get_all_coupons()
    shop_settings = {
        "status": get_setting("shop_status", "open"),
        "open_time": get_setting("shop_open_time", "08:00 AM"),
        "close_time": get_setting("shop_close_time", "11:30 PM"),
        "notice": get_setting("shop_notice", "Shop is open. Instant delivery active!"),
    }

    alert_settings = {
        "low_balance_threshold": get_setting("low_balance_threshold", "3000"),
        "admin_whatsapp_phone": get_setting("admin_whatsapp_phone", "639104568696"),
        "callmebot_api_key": get_setting("callmebot_api_key", ""),
    }

    gemini_api_key = get_setting("gemini_api_key", "")
    smtp_password = get_setting("smtp_password", "") or get_setting("email_app_password", "")
    tickets = get_all_admin_tickets(limit=30)
    open_tickets = get_open_tickets_count()
    catalog_products = get_catalog_with_prices()
    stock_intelligence = get_all_products_live_stock()

    return render_template(
        "admin.html",
        logged=True,
        orders=orders,
        users=users,
        stats=stats,
        htg_info=htg_info,
        htg_accounts=htg_accounts,
        banned_devices=banned_devices,
        rating_stats=rating_stats,
        coupons=coupons,
        shop_settings=shop_settings,
        alert_settings=alert_settings,
        gemini_api_key=gemini_api_key,
        smtp_password=smtp_password,
        tickets=tickets,
        open_tickets=open_tickets,
        admin_ff_id=admin_profile.get("ff_id") or ADMIN_FF_ID,
        catalog_products=catalog_products,
        stock_intelligence=stock_intelligence,
        admin_profile=admin_profile,
    )


@app.route("/api/admin/orders/export_csv", methods=["GET"])
def api_admin_export_orders_csv():
    """Exports orders into a downloadable CSV file for easy bookkeeping."""
    if not is_admin_authorized():
        return jsonify({"success": False, "message": "Unauthorized"}), 401
    import io, csv
    orders = get_all_orders(limit=1000)
    output = io.StringIO()
    writer = csv.writer(output)
    writer.writerow([
        "Order Code", "Created Date", "Player ID", "Nickname", "Product",
        "Quantity", "Amount (LKR)", "Status", "Reference / Transaction",
        "Customer Phone", "Customer Name", "Delivery Ref IDs"
    ])
    for o in orders:
        writer.writerow([
            o.get("order_code", ""),
            o.get("created_at", ""),
            o.get("player_id", ""),
            o.get("nickname", ""),
            o.get("product_name", ""),
            o.get("quantity", 1),
            o.get("amount", 0.0),
            o.get("status", ""),
            o.get("tx_reference", ""),
            o.get("customer_phone", ""),
            o.get("customer_name", ""),
            o.get("htg_order_ids", ""),
        ])
    output.seek(0)
    now_date = datetime.now().strftime("%Y%m%d_%H%M%S")
    return Response(
        output.getvalue(),
        mimetype="text/csv",
        headers={"Content-Disposition": f"attachment;filename=SLCAT_Orders_{now_date}.csv"}
    )


@app.route("/api/admin/save_alert_settings", methods=["POST"])
def api_admin_save_alert_settings():
    """Saves low balance threshold and admin whatsapp alert settings."""
    if not is_admin_authorized():
        return jsonify({"success": False, "message": "Unauthorized"}), 401
    data = request.get_json(silent=True) or {}
    threshold = str(data.get("low_balance_threshold", "3000")).strip()
    phone = str(data.get("admin_whatsapp_phone", "639104568696")).strip()
    callmebot_key = str(data.get("callmebot_api_key", "")).strip()

    if threshold:
        try:
            val = float(threshold)
            set_setting("low_balance_threshold", str(val))
        except ValueError:
            pass
    if phone:
        clean_phone = "".join(c for c in phone if c.isdigit())
        if clean_phone:
            set_setting("admin_whatsapp_phone", clean_phone)
    if callmebot_key is not None:
        set_setting("callmebot_api_key", callmebot_key)

    return jsonify({
        "success": True,
        "message": "Alert & Security Settings Saved Successfully!",
        "low_balance_threshold": get_setting("low_balance_threshold", "3000"),
        "admin_whatsapp_phone": get_setting("admin_whatsapp_phone", "639104568696"),
    })


@app.route("/admin/logout")
def admin_logout():
    session.pop("admin_logged", None)
    resp = redirect(url_for("admin_dashboard"))
    resp.set_cookie("slcat_admin_token", "", expires=0)
    return resp


def is_admin_authorized():
    current_pin = get_setting("admin_pin", ADMIN_PIN)
    pin = request.headers.get("X-Admin-PIN") or request.args.get("pin") or (request.is_json and request.json and request.json.get("pin"))
    if pin == current_pin:
        return True
    rem_token = request.cookies.get("slcat_admin_token")
    if rem_token and rem_token == get_setting("admin_remember_token", ""):
        session["admin_logged"] = True
        return True
    return bool(session.get("admin_logged"))


def get_catalog_with_prices():
    """Returns all products with current prices for Admin Direct Top-Up."""
    items = []
    for p in PRODUCT_CATALOG:
        price = get_product_price(p["id"], 0.0)
        items.append({
            "id": p["id"],
            "name": p["name"],
            "category": p.get("category", "Diamonds"),
            "diamonds": p.get("diamonds", ""),
            "price": price,
            "price_formatted": f"Rs. {price:,.2f}",
        })
    return items


@app.route("/api/admin/products", methods=["GET"])
def api_admin_products():
    """Returns products catalog with prices and admin default FF ID."""
    if not is_admin_authorized():
        return jsonify({"success": False, "message": "Unauthorized"}), 401
    return jsonify({
        "success": True,
        "admin_ff_id": ADMIN_FF_ID,
        "products": get_catalog_with_prices()
    })


@app.route("/api/admin/orders", methods=["GET"])
def api_admin_orders():
    """Returns orders, shop settings, and admin stats in JSON format for the Native In-Built App."""
    if not is_admin_authorized():
        return jsonify({"success": False, "message": "Unauthorized"}), 401

    orders = get_all_orders(limit=50)
    stats = get_admin_stats()
    htg_info = check_htg_balance()
    htg_accounts = get_all_htg_accounts_status()
    banned_devices = get_banned_devices()
    rating_stats = get_chat_rating_stats()
    shop_settings = {
        "status": get_setting("shop_status", "open"),
        "open_time": get_setting("shop_open_time", "08:00"),
        "close_time": get_setting("shop_close_time", "23:30"),
        "notice": get_setting("shop_notice", "Shop is open! Orders delivered instantly."),
    }

    return jsonify({
        "success": True,
        "orders": orders,
        "stats": stats,
        "htg_info": htg_info,
        "htg_accounts": htg_accounts,
        "banned_devices": banned_devices,
        "rating_stats": rating_stats,
        "shop_settings": shop_settings,
        "admin_ff_id": ADMIN_FF_ID,
        "catalog_products": get_catalog_with_prices(),
    })


@app.route("/api/admin/reject_order", methods=["POST"])
def api_admin_reject():
    """Rejects an order with an administrative reason."""
    if not is_admin_authorized():
        return jsonify({"success": False, "message": "Unauthorized"}), 401

    data = request.get_json(silent=True) or {}
    order_code = data.get("order_code")
    reason = data.get("reason", "Payment reference verification failed")

    if not order_code:
        return jsonify({"success": False, "message": "Order code required"}), 400

    ok = reject_order(order_code, reason)
    return jsonify({
        "success": ok,
        "message": f"Order {order_code} has been rejected. Reason: {reason}"
    })


@app.route("/api/admin/shop_settings", methods=["GET", "POST"])
def api_admin_shop_settings():
    """Manages shop operating hours and open/closed status."""
    if request.method == "POST":
        if not is_admin_authorized():
            return jsonify({"success": False, "message": "Unauthorized"}), 401

        data = request.get_json(silent=True) or {}
        if "status" in data:
            set_setting("shop_status", data["status"])
        if "open_time" in data:
            ot = str(data["open_time"]).replace(".", ":").strip()
            set_setting("shop_open_time", ot)
        if "close_time" in data:
            ct = str(data["close_time"]).replace(".", ":").strip()
            set_setting("shop_close_time", ct)
        if "notice" in data:
            set_setting("shop_notice", data["notice"])

        return jsonify({
            "success": True,
            "message": "Shop settings updated successfully!",
            "settings": {
                "status": get_setting("shop_status", "open"),
                "open_time": get_setting("shop_open_time", "08:00 AM"),
                "close_time": get_setting("shop_close_time", "11:30 PM"),
                "notice": get_setting("shop_notice", ""),
            }
        })

    return jsonify({
        "success": True,
        "status": get_setting("shop_status", "open"),
        "open_time": get_setting("shop_open_time", "08:00 AM"),
        "close_time": get_setting("shop_close_time", "11:30 PM"),
        "notice": get_setting("shop_notice", ""),
    })


@app.route("/api/admin/order_lookup/<order_code>", methods=["GET"])
def api_admin_order_lookup(order_code):
    """Admin tool to quickly inspect an order before delivering."""
    if not is_admin_authorized():
        return jsonify({"success": False, "message": "Unauthorized"}), 401

    clean_code = str(order_code).strip().upper()
    order = get_order(clean_code)
    if not order:
        return jsonify({"success": False, "message": f"Order `{clean_code}` පද්ධතියේ හමු නොවීය."}), 404

    return jsonify({
        "success": True,
        "order": order
    })


@app.route("/api/admin/deliver_order", methods=["POST"])
def api_admin_deliver():
    """Admin 1-click order fulfillment to HTG Digital or manual delivery marking."""
    if not is_admin_authorized():
        return jsonify({"success": False, "message": "Unauthorized"}), 401

    data = request.get_json(silent=True) or {}
    order_code = str(data.get("order_code", "")).strip().upper()
    mode = data.get("mode", "htg")

    if not order_code:
        return jsonify({"success": False, "message": "Order Code එකක් ඇතුළත් කිරීම අනිවාර්ය වේ."}), 400

    order = get_order(order_code)
    if not order:
        return jsonify({"success": False, "message": f"Order `{order_code}` සොයාගත නොහැක."}), 404

    if mode == "manual":
        from database import mark_order_completed
        manual_ref = data.get("manual_ref", "MANUAL-DELIVERED-BY-ADMIN")
        ok = mark_order_completed(order_code, manual_ref)
        if ok:
            return jsonify({
                "success": True,
                "message": f"✅ Order `{order_code}` සාර්ථකව Manual Delivered ලෙස සටහන් විය! (Ref: {manual_ref})",
                "order_ids": [manual_ref],
                "status": "completed"
            })
        else:
            return jsonify({"success": False, "message": f"Order `{order_code}` Status යාවත්කාලීන කිරීමට නොහැකි විය."}), 400

    # HTG automated delivery
    account_key = data.get("account_key")
    res = process_and_deliver_order(order_code, force=True, account_key=account_key)
    return jsonify(res)


@app.route("/api/admin/refund_order", methods=["POST"])
def api_admin_refund():
    """Admin 1-click manual refund back to customer wallet for failed/rejected orders."""
    if not is_admin_authorized():
        return jsonify({"success": False, "message": "Unauthorized"}), 401

    data = request.get_json(silent=True) or {}
    order_code = str(data.get("order_code", "")).strip().upper()
    reason = str(data.get("reason", "Refunded by Admin (HTG Delivery Failed)")).strip()

    if not order_code:
        return jsonify({"success": False, "message": "Order Code එකක් ඇතුළත් කිරීම අනිවාර්ය වේ."}), 400

    order = get_order(order_code)
    if not order:
        return jsonify({"success": False, "message": f"Order `{order_code}` හමු නොවීය."}), 404

    ref_res = refund_failed_order(order_code, reason)
    if ref_res.get("success"):
        return jsonify({
            "success": True,
            "message": f"✅ Order `{order_code}` සාර්ථකව Refund විය! Customer Wallet වෙත මුදල බැර විය.",
            "refunded": True,
            "order": get_order(order_code),
        })
    return jsonify({
        "success": False,
        "message": ref_res.get("message", f"Order `{order_code}` refund කිරීමට නොහැකි විය."),
    }), 400


@app.route("/api/admin/save_profile", methods=["POST"])
def api_admin_save_profile():
    """Admin Profile, Avatar, Name, Phone, UID & PIN update."""
    if not is_admin_authorized():
        return jsonify({"success": False, "message": "Unauthorized"}), 401

    data = request.get_json(silent=True) or {}
    display_name = str(data.get("display_name", "")).strip() or "Crazy Owner"
    avatar = str(data.get("avatar", "")).strip() or "👑"
    phone = str(data.get("whatsapp_phone", "")).strip()
    admin_ff_id = str(data.get("admin_ff_id", "")).strip()
    current_pin = str(data.get("current_pin", "")).strip()
    new_pin = str(data.get("new_pin", "")).strip()

    # PIN Change verification if new_pin is provided
    if new_pin:
        active_pin = get_setting("admin_pin", ADMIN_PIN)
        if current_pin != active_pin:
            return jsonify({"success": False, "message": "දැනට පවතින Security PIN එක වැරදියි! කරුණාකර නිවැරදි PIN එක ඇතුළත් කරන්න."}), 400
        if len(new_pin) < 4 or not new_pin.isdigit():
            return jsonify({"success": False, "message": "නව Security PIN එක ඉලක්කම් 4 කින් (Digits 4) යුක්ත විය යුතුය."}), 400
        set_setting("admin_pin", new_pin)

    set_setting("admin_display_name", display_name)
    set_setting("admin_avatar", avatar)
    if phone:
        set_setting("admin_whatsapp_phone", phone)
    if admin_ff_id:
        set_setting("admin_ff_id", admin_ff_id)

    return jsonify({
        "success": True,
        "message": "Admin Profile සාර්ථකව Save විය! ✅",
        "profile": {
            "display_name": display_name,
            "avatar": avatar,
            "phone": phone or get_setting("admin_whatsapp_phone", "639104568696"),
            "admin_ff_id": admin_ff_id or get_setting("admin_ff_id", ADMIN_FF_ID),
        }
    })


@app.route("/api/admin/recheck_order_queue", methods=["POST"])
def api_admin_recheck_queue():
    """Admin tool to re-verify an order's queue status in HTG Digital and sync status & auto-refund."""
    if not is_admin_authorized():
        return jsonify({"success": False, "message": "Unauthorized"}), 401

    data = request.get_json(silent=True) or {}
    order_code = data.get("order_code")
    order = get_order(order_code)
    if not order:
        return jsonify({"success": False, "message": "Order not found"}), 404

    htg_id = str(order.get("htg_order_ids") or "").split(" ")[0].split("(")[0].strip()
    from htg_engine import check_htg_order_queue
    htg_item = check_htg_order_queue(order_id=htg_id if htg_id and htg_id.startswith(("LVL-", "MY-", "ODR-")) else None, player_id=order["player_id"])

    if not htg_item:
        return jsonify({"success": False, "message": f"HTG Order record not found in history for {order['player_id']}."})

    qst = str(htg_item.get("queue_status", "")).lower()
    res_id = str(htg_item.get("result_id", ""))
    real_oid = htg_item.get("orderid", htg_id)

    if qst == "done":
        full_id = f"{real_oid} (Ref: {res_id})" if res_id and res_id != "-" else real_oid
        mark_order_completed(order_code, full_id)
        return jsonify({
            "success": True,
            "status": "completed",
            "message": f"HTG Queue status: DONE! Items confirmed delivered to {order['player_id']} (Ref: {full_id}).",
        })
    elif qst == "failed":
        fail_msg = f"HTG queue rejected order ({real_oid}). Free Fire UID {order['player_id']} ineligible, already claimed, or server issue."
        mark_order_failed(order_code, fail_msg)
        refunded = False
        if order.get("user_id"):
            try:
                credit_wallet(
                    user_id=order["user_id"],
                    amount=float(order["amount"]),
                    description=f"Auto-Refund: Order {order_code} queue failed on HTG",
                    reference_code=f"REFUND-{order_code}",
                )
                refunded = True
            except Exception:
                pass
        return jsonify({
            "success": False,
            "status": "failed",
            "message": f"HTG Queue status: FAILED. Order marked failed." + (" Rs. " + str(order['amount']) + " refunded to customer wallet!" if refunded else ""),
        })
    else:
        return jsonify({
            "success": True,
            "status": qst,
            "message": f"HTG Queue is currently: {qst.upper()}.",
        })



@app.route("/api/admin/direct_topup", methods=["POST"])
def api_admin_direct_topup():
    """
    Direct Cash / In-Hand Top-Up API for Admin.
    Allows instant Free Fire top-up for local village customers, friends, or admin self (UID: 2332538025)
    who pay by cash. Instantly fulfills via HTG Digital and records in sales history.
    """
    if not is_admin_authorized():
        return jsonify({"success": False, "message": "Unauthorized"}), 401

    data = request.get_json(silent=True) or request.form.to_dict() or {}
    player_id = str(data.get("player_id", "")).strip()
    product_id = str(data.get("product_id", "")).strip()
    nickname = str(data.get("nickname", "")).strip()
    customer_name = str(data.get("customer_name", "")).strip() or "Cash Customer (ගමේ/යාලුවෙක්)"
    customer_phone = str(data.get("customer_phone", "")).strip()
    notes = str(data.get("notes", "")).strip()
    try:
        quantity = max(1, int(data.get("quantity", 1)))
    except (ValueError, TypeError):
        quantity = 1

    if not player_id:
        return jsonify({"success": False, "message": "Player Free Fire UID එක ඇතුළත් කරන්න."}), 400

    if not product_id:
        return jsonify({"success": False, "message": "Package එකක් තෝරන්න."}), 400

    # Auto-resolve nickname if missing or generic
    if not nickname or nickname == "Player":
        uid_check = check_player_uid(player_id)
        if uid_check.get("success") and uid_check.get("nickname"):
            nickname = uid_check["nickname"]
        else:
            nickname = "Player"

    # Find product info
    product = next((p for p in PRODUCT_CATALOG if p["id"] == product_id), None)
    product_name = product["name"] if product else f"Package {product_id}"

    # Price determination
    custom_amount = data.get("amount")
    if custom_amount is not None and str(custom_amount).strip() != "":
        try:
            amount = round(float(custom_amount), 2)
        except (ValueError, TypeError):
            amount = round(get_product_price(product_id, 0.0) * quantity, 2)
    else:
        amount = round(get_product_price(product_id, 0.0) * quantity, 2)

    # 1. Create order record
    order_code = create_order(
        player_id=player_id,
        nickname=nickname,
        product_id=product_id,
        product_name=product_name,
        amount=amount,
        qr_payload="DIRECT_CASH_TOPUP",
        quantity=quantity,
        customer_name=customer_name,
        customer_phone=customer_phone,
    )

    # Reference note
    tx_ref = f"💵 CASH-IN-HAND ({customer_name})"
    if notes:
        tx_ref += f" - {notes}"
    update_order_payment(order_code, tx_reference=tx_ref)

    # 2. Execute instant HTG delivery
    delivery_res = process_and_deliver_order(order_code)

    if delivery_res.get("success"):
        return jsonify({
            "success": True,
            "message": f"✅ සාර්ථකයි! {product_name} Top-Up එක {nickname} ({player_id}) වෙත ක්ෂණිකව Deliver විය!",
            "order_code": order_code,
            "player_id": player_id,
            "nickname": nickname,
            "product_name": product_name,
            "amount": amount,
            "htg_order_ids": delivery_res.get("order_ids", ""),
            "delivery": delivery_res,
        })
    else:
        err_msg = delivery_res.get("message", "Unknown HTG error")
        return jsonify({
            "success": False,
            "message": f"⚠️ Order එක ({order_code}) සටහන් විය, නමුත් HTG Delivery අසාර්ථකයි: {err_msg}. කරුණාකර HTG Balance හෝ Session පරීක්ෂා කර Admin Dashboard එකෙන් නැවත 'Deliver' ඔබන්න.",
            "order_code": order_code,
            "player_id": player_id,
            "nickname": nickname,
            "product_name": product_name,
            "amount": amount,
            "delivery": delivery_res,
        }), 400


@app.route("/api/admin/create_visa_recharge", methods=["POST"])
def api_admin_create_visa_recharge():
    """Generates official Visa Pay payment link on HTG Digital for admin wallet recharge."""
    if not is_admin_authorized():
        return jsonify({"success": False, "message": "Unauthorized"}), 401

    data = request.get_json(silent=True) or {}
    amount = float(data.get("amount", 5000.0))
    account_key = data.get("account_id") or data.get("account_key")
    if amount < 100:
        return jsonify({"success": False, "message": "Minimum recharge amount is LKR 100"}), 400

    res = create_visa_payment_link(amount=amount, account_key=account_key)
    return jsonify(res)


@app.route("/api/admin/sync_visa_transaction", methods=["POST"])
def api_admin_sync_visa_transaction():
    """Manually links a paid GenieBiz transaction to HTG reseller wallet and checks status."""
    if not is_admin_authorized():
        return jsonify({"success": False, "message": "Unauthorized"}), 401

    data = request.get_json(silent=True) or {}
    tx_id = (data.get("tx_id") or data.get("transaction_id") or "").strip()
    try:
        amount = float(data.get("amount", 5000.0))
    except Exception:
        amount = 5000.0
    account_key = data.get("account_id") or data.get("account_key")

    if not tx_id:
        return jsonify({"success": False, "message": "Transaction Reference / ID is required."}), 400

    res = sync_missing_visa_recharge(tx_id=tx_id, amount=amount, account_key=account_key)
    return jsonify(res)



@app.route("/api/admin/refresh_htg_balance", methods=["POST", "GET"])
def api_admin_refresh_htg_balance():
    """Triggers HTG check_transactions and returns live balances for all accounts."""
    if not is_admin_authorized():
        return jsonify({"success": False, "message": "Unauthorized"}), 401

    check_visa_transactions()
    accounts_status = refresh_all_accounts_balance()
    active_info = check_htg_balance()
    invalidate_stock_cache()
    return jsonify({
        "success": True,
        "balance": active_info.get("balance", 0.0),
        "balance_formatted": f"LKR {active_info.get('balance', 0.0):,.2f}",
        "username": active_info.get("username", "SL-cat-app"),
        "valid": active_info.get("valid", False),
        "accounts_data": accounts_status,
    })


@app.route("/api/admin/stock_intelligence", methods=["GET"])
def api_admin_stock_intelligence():
    """Returns live stock calculation, reseller profit margins, and HTG rates."""
    if not is_admin_authorized():
        return jsonify({"success": False, "message": "Unauthorized"}), 401
    force = request.args.get("refresh", "").lower() in ("1", "true")
    data = get_all_products_live_stock(force_refresh=force)
    return jsonify({"success": True, "data": data})


@app.route("/api/admin/stock_settings", methods=["POST"])
def api_admin_stock_settings():
    """Updates stock calculation mode and safety reserve buffer."""
    if not is_admin_authorized():
        return jsonify({"success": False, "message": "Unauthorized"}), 401
    req_data = request.get_json(silent=True) or {}
    mode = req_data.get("mode", "combined")
    try:
        safety_reserve = float(req_data.get("safety_reserve", 0.0))
    except Exception:
        safety_reserve = 0.0
    overrides = req_data.get("overrides")
    save_stock_configuration(mode=mode, safety_reserve=safety_reserve, overrides=overrides)
    updated_data = get_all_products_live_stock(force_refresh=True)
    return jsonify({
        "success": True,
        "message": "Stock settings updated successfully!",
        "data": updated_data,
    })


@app.route("/api/admin/stock_sync", methods=["POST"])
def api_admin_stock_sync():
    """Forces a live balance query to HTG and recalculates all product stocks."""
    if not is_admin_authorized():
        return jsonify({"success": False, "message": "Unauthorized"}), 401
    data = force_sync_htg_and_refresh_stock()
    return jsonify({
        "success": True,
        "message": "HTG balances and rates successfully synchronized with live store!",
        "data": data,
    })


@app.route("/api/admin/htg/accounts", methods=["GET"])
def api_admin_htg_accounts():
    """Returns overview of all HTG accounts with live/cached balances."""
    if not is_admin_authorized():
        return jsonify({"success": False, "message": "Unauthorized"}), 401
    return jsonify({"success": True, "data": get_all_htg_accounts_status()})


@app.route("/api/admin/htg/switch_active", methods=["POST"])
def api_admin_htg_switch_active():
    """Switches the active / primary HTG account."""
    if not is_admin_authorized():
        return jsonify({"success": False, "message": "Unauthorized"}), 401
    data = request.get_json(silent=True) or {}
    account_id = data.get("account_id")
    if not account_id:
        return jsonify({"success": False, "message": "Account ID is required"}), 400
    ok = set_active_account(account_id)
    if ok:
        return jsonify({
            "success": True,
            "message": f"Active account switched to '{account_id}' successfully!",
            "data": get_all_htg_accounts_status(),
        })
    return jsonify({"success": False, "message": f"Failed to switch account '{account_id}'"}), 400


@app.route("/api/admin/htg/update_cookies", methods=["POST"])
def api_admin_htg_update_cookies():
    """Updates session cookies/JSON for a specific HTG account."""
    if not is_admin_authorized():
        return jsonify({"success": False, "message": "Unauthorized"}), 401
    data = request.get_json(silent=True) or {}
    account_id = data.get("account_id")
    cookies_input = data.get("cookies") or data.get("raw_input")
    account_name = data.get("name")
    if not account_id or not cookies_input:
        return jsonify({"success": False, "message": "Account ID and cookies are required"}), 400

    res = update_account_cookies(account_id, cookies_input, account_name)
    return jsonify(res)


@app.route("/api/admin/htg/toggle_failover", methods=["POST"])
def api_admin_htg_toggle_failover():
    """Toggles auto-failover on/off."""
    if not is_admin_authorized():
        return jsonify({"success": False, "message": "Unauthorized"}), 401
    data = request.get_json(silent=True) or {}
    enabled = data.get("enabled", True)
    set_auto_failover(enabled)
    return jsonify({
        "success": True,
        "auto_failover": enabled,
        "message": f"Auto-failover is now {'ENABLED' if enabled else 'DISABLED'}.",
    })


@app.route("/api/admin/check_new_payments", methods=["GET"])
def api_admin_check_new_payments():
    """Polls for new submitted payments or unconfirmed orders for audio/push notification."""
    if not is_admin_authorized():
        return jsonify({"success": False, "message": "Unauthorized"}), 401

    # Automatically reject orders older than 15 minutes
    auto_reject_stale_orders(max_age_minutes=15)

    with get_connection() as conn:
        cur = conn.cursor()
        cur.execute(
            """
            SELECT order_code, player_id, nickname, product_name, amount, status, tx_reference, updated_at
            FROM orders
            WHERE status = 'payment_submitted'
            ORDER BY id DESC LIMIT 5
            """
        )
        submitted = [dict(r) for r in cur.fetchall()]

        cur.execute(
            """
            SELECT id, source, amount, reference, is_matched, created_at
            FROM bank_notifications
            ORDER BY id DESC LIMIT 1
            """
        )
        notif_row = cur.fetchone()
        latest_notif = dict(notif_row) if notif_row else None

    v_stats = get_visitor_stats()
    open_tickets = get_open_tickets_count()
    low_bal_alert = check_and_trigger_low_balance_alert()

    return jsonify({
        "success": True,
        "has_pending": len(submitted) > 0,
        "pending_count": len(submitted),
        "pending_orders": submitted,
        "latest_notification": latest_notif,
        "open_tickets_count": open_tickets,
        "low_balance_alert": low_bal_alert,
        "live_visitors": v_stats.get("live_visitors", 0),
        "today_visitors": v_stats.get("today_visitors", 0),
        "total_visitors": v_stats.get("total_visitors", 0),
        "total_pageviews": v_stats.get("total_pageviews", 0),
        "total_users": v_stats.get("total_users", 0),
        "total_players": v_stats.get("total_players", 0),
    })


@app.route("/api/ai_chat", methods=["POST"])
def api_ai_chat():
    """Handles real-time 24/7 human-like live customer care chat from website visitors with 10 rotating agents."""
    from ai_assistant import process_ai_chat_message
    data = request.get_json(silent=True) or {}
    message = str(data.get("message", "")).strip()
    if not message:
        return jsonify({"success": False, "reply": "කරුණාකර ඔබගේ පණිවිඩය මෙහි Type කරන්න."}), 400

    history = data.get("history") or []
    agent_info = data.get("agent") or {}
    session_user = {
        "user_id": session.get("user_id"),
        "user_name": session.get("user_name"),
        "user_phone": session.get("user_phone"),
    }
    res = process_ai_chat_message(message, history=history, session_user=session_user, agent_info=agent_info)
    agent_display_name = agent_info.get("name_si") or "කවිඳු (Kavindu)"
    agent_display_role = agent_info.get("role_si") or "Senior Support Executive"
    return jsonify({
        "success": True,
        "reply": res.get("reply", ""),
        "messages": res.get("messages", [res.get("reply", "")]),
        "action": res.get("action", "none"),
        "order_card": res.get("order_card"),
        "whatsapp_url": res.get("whatsapp_url"),
        "agent_name": agent_display_name,
        "agent_role": agent_display_role,
    })


@app.route("/api/ai_chat/upload_slip", methods=["POST"])
def api_ai_chat_upload_slip():
    """Handles bank slip/screenshot upload directly inside AI Live Chat."""
    slip_file = request.files.get("slip")
    order_code = request.form.get("order_code", "").strip()
    user_id = session.get("user_id")

    if not slip_file or not slip_file.filename:
        return jsonify({"success": False, "message": "කරුණාකර වලංගු Image එකක් තෝරන්න."}), 400

    filename = f"chat_slip_{int(time.time())}_{uuid.uuid4().hex[:6]}.jpg"
    filepath = os.path.join(app.config["UPLOAD_FOLDER"], filename)
    slip_file.save(filepath)
    rel_path = f"uploads/{filename}"

    # Find target order
    target_order = None
    if order_code:
        target_order = get_order(order_code)
    elif user_id:
        user_orders = get_user_orders(user_id)
        for o in user_orders:
            if o["status"] in ("pending_payment", "awaiting_bank_confirmation", "payment_submitted"):
                target_order = o
                break

    if target_order:
        if target_order.get("status") == "completed":
            return jsonify({
                "success": True,
                "verified": True,
                "message": "මෙම ඇණවුම දැනටමත් සාර්ථකව සම්පූර්ණ කර ඇත (Already Completed)!",
            })

        # Attempt Gemini Vision OCR to read Ref ID from the slip image
        extracted_ref = None
        try:
            from ai_assistant import extract_slip_info_with_gemini
            extracted = extract_slip_info_with_gemini(filepath)
            if extracted and extracted.get("ref_id"):
                extracted_ref = str(extracted["ref_id"]).strip()
        except Exception:
            pass

        update_order_payment(target_order["order_code"], tx_reference=extracted_ref, slip_path=rel_path)
        with get_connection() as conn:
            conn.cursor().execute(
                "UPDATE orders SET status = CASE WHEN status = 'completed' THEN 'completed' ELSE 'payment_submitted' END, error_message = NULL, updated_at = ? WHERE order_code = ?",
                (datetime.now().strftime("%Y-%m-%d %H:%M:%S"), target_order["order_code"])
            )
            conn.commit()

        # Check for immediate match with bank notification!
        match = find_matching_notification(target_order["amount"])
        if match:
            mark_notification_matched(match["id"], target_order["order_code"])
            fulfill_res = process_and_deliver_order(target_order["order_code"])
            ref_msg = f" (Ref ID: `{extracted_ref}`)" if extracted_ref else ""
            return jsonify({
                "success": True,
                "verified": True,
                "reply": f"🎉 සහෝ, ඔයා එවපු Bank Slip එක පරීක්ෂා කර බැංකු ගිණුම් වාර්තාව සමඟ තහවුරු විය{ref_msg}! ඔයාගේ Order Code `{target_order['order_code']}` එක සාර්ථකව Complete කර Diamonds Deliver කරන ලදී! 💎",
                "order_code": target_order["order_code"]
            })

        ref_info = f"\nSlip එකෙන් හඳුනාගත් Reference අංකය: `{extracted_ref}`" if extracted_ref else ""
        return jsonify({
            "success": True,
            "verified": False,
            "reply": f"📸 ස්තූතියි සහෝ! ඔයා එවපු Slip එක Order `{target_order['order_code']}` එකට සම්බන්ධ කළා.{ref_info}\nබැංකු වාර්තාව තහවුරු වන තෙක් හෝ Admin පරික්ෂාව සඳහා මෙම Order එක Cancel නොවී ආරක්ෂිතව තබා ඇත 🛡️",
            "order_code": target_order["order_code"]
        })

    return jsonify({
        "success": True,
        "verified": False,
        "reply": "📸 ස්තූතියි සහෝ! ඔබ එවූ Bank Slip එක ලැබුණි. කරුණාකර ඔබගේ Order Code එක (CAT-XXXXXXXX) මෙහි Type කරන්න, මම එය මේ Slip එකට සම්බන්ධ කර තහවුරු කර දෙන්නම්."
    })


@app.route("/api/ai_chat/rate", methods=["POST"])
def api_ai_chat_rate():
    """Saves user rating for live support chat."""
    data = request.get_json(silent=True) or {}
    try:
        rating = int(data.get("rating", 5))
    except (ValueError, TypeError):
        rating = 5
    comment = str(data.get("comment", "")).strip()
    user_id = session.get("user_id")
    device_id = request.headers.get("X-Device-Id") or request.cookies.get("slcat_device_uuid")
    save_chat_rating(rating, comment, user_id, device_id)
    return jsonify({
        "success": True,
        "reply": "ගොඩක් ස්තූතියි සහෝ ඔයාගේ වටිනා Rating එකට! ඔයාට සතුටුයි නම් මටත් සතුටුයි 😊 වෙන මොනවා හරි උදව්වක් ඕන නම් ඕනෑම වෙලාවක කතා කරන්න. ජය වේවා! 🎮💎"
    })


# =========================================================================
# 📨 Direct Web Contact & Admin Tickets API (100% On-Web, No WhatsApp)
# =========================================================================

@app.route("/api/contact_admin", methods=["POST"])
def api_contact_admin():
    """Direct web message submission to Owner/Admin (no WhatsApp required)."""
    data = request.get_json(silent=True) or request.form.to_dict() or {}
    name = str(data.get("name", "")).strip() or "Website Visitor"
    contact = str(data.get("contact", "")).strip() or (session.get("user_phone") or "Web Chat")
    message = str(data.get("message", "")).strip()
    subject = str(data.get("subject", "Customer Direct Help")).strip()
    player_id = str(data.get("player_id", "")).strip() or None
    order_code = str(data.get("order_code", "")).strip() or None
    user_id = session.get("user_id")

    if not message:
        return jsonify({"success": False, "message": "කරුණාකර ඔබගේ පණිවිඩය ඇතුළත් කරන්න."}), 400

    ticket_code = create_admin_ticket(
        sender_name=name,
        sender_contact=contact,
        message=message,
        subject=subject,
        player_id=player_id,
        order_code=order_code,
        user_id=user_id,
    )

    return jsonify({
        "success": True,
        "ticket_code": ticket_code,
        "message": f"ඔබගේ පණිවිඩය සාර්ථකව Admin/Owner වෙත යොමු කරන ලදී! Ticket Code: {ticket_code}. Admin විසින් ඉතා ඉක්මනින් මෙහි පිළිතුරු සපයනු ඇත."
    })


@app.route("/api/ticket_status/<ticket_code>", methods=["GET"])
def api_ticket_status(ticket_code):
    """Fetches status and admin reply for a direct ticket."""
    tkt = get_admin_ticket(ticket_code)
    if not tkt:
        return jsonify({"success": False, "message": "Ticket එක හමු නොවීය."}), 404
    return jsonify({
        "success": True,
        "ticket": tkt
    })


@app.route("/api/admin/tickets", methods=["GET"])
def api_admin_tickets():
    """Returns all customer direct support tickets for admin dashboard/app."""
    if not is_admin_authorized():
        return jsonify({"success": False, "message": "Unauthorized"}), 401
    tickets = get_all_admin_tickets(limit=100)
    return jsonify({
        "success": True,
        "tickets": tickets,
        "open_count": get_open_tickets_count()
    })


def dispatch_web_push(ticket_code: str, title: str, body: str, url: str = "/"):
    """Sends background Web Push notification to subscribed browser/device endpoints."""
    from database import get_push_subscriptions_for_ticket
    subs = get_push_subscriptions_for_ticket(ticket_code)
    if not subs:
        return 0

    sent_count = 0
    payload = json.dumps({
        "title": title,
        "body": body,
        "url": url,
        "ticket_code": ticket_code,
        "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    })

    for s in subs:
        ep = s.get("endpoint")
        if not ep:
            continue
        try:
            headers = {"Content-Type": "application/json", "TTL": "86400"}
            requests.post(ep, data=payload, headers=headers, timeout=5)
            sent_count += 1
        except Exception as ex:
            logger.debug(f"Web push dispatch note: {ex}")

    return sent_count


@app.route("/api/admin/reply_ticket", methods=["POST"])
def api_admin_reply_ticket():
    """Admin responds directly to a customer's web ticket."""
    if not is_admin_authorized():
        return jsonify({"success": False, "message": "Unauthorized"}), 401
    data = request.get_json(silent=True) or {}
    ticket_code = str(data.get("ticket_code", "")).strip()
    reply_text = str(data.get("reply", "")).strip()
    if not ticket_code or not reply_text:
        return jsonify({"success": False, "message": "Ticket Code and Reply are required"}), 400

    ok = reply_admin_ticket(ticket_code, reply_text)
    if ok:
        # Trigger offline Web Push notification to customer device
        threading.Thread(
            target=dispatch_web_push,
            args=(ticket_code, "⚡ SLCAT Admin Support Reply", f"Admin: {reply_text[:120]}", f"/#ticket_{ticket_code}"),
            daemon=True
        ).start()
        return jsonify({"success": True, "message": "Reply sent successfully!"})
    return jsonify({"success": False, "message": "Ticket not found"}), 404


@app.route("/api/push/subscribe", methods=["POST"])
def api_push_subscribe():
    """Registers Web Push subscription endpoint from browser service worker."""
    data = request.get_json(silent=True) or {}
    subscription = data.get("subscription") or {}
    endpoint = subscription.get("endpoint") or data.get("endpoint")
    keys = subscription.get("keys") or {}
    p256dh = keys.get("p256dh") or data.get("p256dh")
    auth = keys.get("auth") or data.get("auth")
    user_id = session.get("user_id")
    ticket_code = data.get("ticket_code")
    device_id = data.get("device_id") or request.cookies.get("slcat_device_uuid")

    if not endpoint:
        return jsonify({"success": False, "message": "Endpoint required"}), 400

    from database import save_push_subscription
    ok = save_push_subscription(
        endpoint=endpoint,
        p256dh=p256dh,
        auth=auth,
        user_id=user_id,
        ticket_code=ticket_code,
        device_id=device_id,
    )
    return jsonify({"success": ok, "message": "Push notifications subscribed!"})


@app.route("/api/admin/backup_db", methods=["GET", "POST"])
def api_admin_backup_db():
    """Triggers an atomic database backup and optionally downloads it."""
    if not is_admin_authorized():
        return jsonify({"success": False, "message": "Unauthorized"}), 401

    from database import backup_database
    res = backup_database()
    if request.args.get("download") == "true":
        return send_file(res["backup_path"], as_attachment=True, download_name=res["backup_filename"])
    return jsonify(res)



@app.route("/api/ticket/customer_reply", methods=["POST"])
def api_ticket_customer_reply():
    """Allows customer to send a follow-up reply to the Admin under an existing ticket."""
    data = request.get_json(silent=True) or request.form.to_dict() or {}
    ticket_code = str(data.get("ticket_code", "")).strip()
    message = str(data.get("message", "")).strip()
    sender_name = str(data.get("name", "")).strip() or None

    if not ticket_code or not message:
        return jsonify({"success": False, "message": "Ticket Code and Message are required."}), 400

    ticket = get_admin_ticket(ticket_code)
    if not ticket:
        return jsonify({"success": False, "message": "Ticket එක හමු නොවීය."}), 404

    ok = customer_reply_admin_ticket(ticket_code, message, sender_name=sender_name)
    if ok:
        updated_ticket = get_admin_ticket(ticket_code)
        return jsonify({
            "success": True,
            "message": "ඔබගේ පිළිතුර Admin වෙත යොමු කරන ලදී!",
            "ticket": updated_ticket
        })
    return jsonify({"success": False, "message": "පිළිතුර යැවීමට නොහැකි විය."}), 500


@app.route("/api/admin/save_gemini_key", methods=["POST"])
def api_admin_save_gemini_key():
    """Saves Google Gemini Generative AI API key for Kavindu Support Agent."""
    if not is_admin_authorized():
        return jsonify({"success": False, "message": "Unauthorized"}), 401
    data = request.get_json(silent=True) or {}
    key = str(data.get("gemini_api_key", "")).strip()
    set_setting("gemini_api_key", key)
    return jsonify({
        "success": True,
        "message": "Google Gemini API Key එක සාර්ථකව යාවත්කාලීන කරන ලදී!",
        "has_key": bool(key)
    })


@app.route("/api/admin/save_smtp_password", methods=["POST"])
def api_admin_save_smtp_password():
    """Saves Gmail App Password for slcatapp@gmail.com in settings."""
    if not is_admin_authorized():
        return jsonify({"success": False, "message": "Unauthorized"}), 401
    data = request.get_json(silent=True) or {}
    pwd = str(data.get("smtp_password", "")).strip().replace(" ", "")
    set_setting("smtp_password", pwd)
    set_setting("email_app_password", pwd)
    return jsonify({
        "success": True,
        "message": "Gmail App Password එක සාර්ථකව Save විය! දැන් Receipts & OTP යවනු ලැබේ.",
        "has_password": bool(pwd)
    })


@app.route("/api/admin/send_test_email", methods=["POST"])
def api_admin_send_test_email():
    """Sends a test sample order receipt to verify Gmail SMTP configuration."""
    if not is_admin_authorized():
        return jsonify({"success": False, "message": "Unauthorized"}), 401

    data = request.get_json(silent=True) or {}
    to_email = str(data.get("test_email", "")).strip()
    if not to_email or "@" not in to_email:
        return jsonify({"success": False, "message": "වලංගු ඊමේල් ලිපිනයක් ඇතුළත් කරන්න."}), 400

    from mail_service import get_smtp_password, _send_order_receipt_email_sync
    pwd = get_smtp_password()
    if not pwd:
        return jsonify({
            "success": False,
            "message": "Gmail App Password එක තවමත් Save කර නැත. කරුණාකර ඉහත ඇති 16-Letter App Password එක ඇතුළත් කර Save කරන්න."
        }), 400

    sample_order = {
        "order_code": "TEST-" + datetime.now().strftime("%H%M%S"),
        "player_id": "1234567890",
        "player_nickname": "ProGamer_SL",
        "product_name": "115 Diamonds (Test Receipt)",
        "amount": 250.00,
        "created_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
        "customer_name": "SL CAT Administrator"
    }

    try:
        sent = _send_order_receipt_email_sync(to_email, sample_order)
        if sent:
            return jsonify({
                "success": True,
                "message": f"✅ Test Receipt ඊමේල් එක සාර්ථකව {to_email} ලිපිනයට යවන ලදී! ඔබගේ Inbox හෝ Spam ෆෝල්ඩරය පරීක්ෂා කරන්න."
            })
        else:
            return jsonify({
                "success": False,
                "message": "❌ ඊමේල් එක යැවීම අසාර්ථක විය. ඔබගේ Gmail App Password එක නිවැරදිද සහ 2-Step Verification සක්‍රීය කර ඇත්දැයි පරීක්ෂා කරන්න."
            }), 500
    except Exception as e:
        return jsonify({
            "success": False,
            "message": f"SMTP Error: {str(e)}"
        }), 500


@app.route("/api/admin/ban_device", methods=["POST"])
def api_admin_ban_device():
    """Permanently bans a device ID, IP, or user."""
    if not is_admin_authorized():
        return jsonify({"success": False, "message": "Unauthorized"}), 401
    data = request.get_json(silent=True) or {}
    device_id = str(data.get("device_id", "")).strip()
    ip_address = str(data.get("ip_address", "")).strip()
    user_id = data.get("user_id")
    reason = str(data.get("reason", "Fraudulent Activity / Fake Slip Submission")).strip()

    if not device_id and not ip_address and not user_id:
        return jsonify({"success": False, "message": "Device ID, IP, or User ID is required"}), 400

    if device_id:
        ban_device(device_id, ip_address, reason, banned_by="admin")
    if user_id:
        ban_user(int(user_id), reason)
    return jsonify({"success": True, "message": "උපාංගය සහ ගිණුම ස්ථිරවම තහනම් කරන ලදී (Permanently Banned)!"})


@app.route("/api/admin/unban_device", methods=["POST"])
def api_admin_unban_device():
    """Removes a ban on a device or user."""
    if not is_admin_authorized():
        return jsonify({"success": False, "message": "Unauthorized"}), 401
    data = request.get_json(silent=True) or {}
    device_id = str(data.get("device_id", "")).strip()
    user_id = data.get("user_id")
    if device_id:
        unban_device(device_id)
    if user_id:
        unban_user(int(user_id))
    return jsonify({"success": True, "message": "තහනම සාර්ථකව ඉවත් කරන ලදී (Unbanned)!"})


@app.route("/api/admin/coupon/add", methods=["POST"])
def api_admin_add_coupon():
    """Adds a new promo code/coupon."""
    if not is_admin_authorized():
        return jsonify({"success": False, "message": "Unauthorized"}), 401
    data = request.get_json(silent=True) or {}
    code = str(data.get("code", "")).strip().upper()
    discount_type = str(data.get("discount_type", "fixed")).strip()
    try:
        discount_value = float(data.get("discount_value", 0))
    except (ValueError, TypeError):
        discount_value = 0.0
    try:
        min_order_amount = float(data.get("min_order_amount", 0))
    except (ValueError, TypeError):
        min_order_amount = 0.0
    try:
        max_uses = int(data.get("max_uses", 1000))
    except (ValueError, TypeError):
        max_uses = 1000
    expires_at = data.get("expires_at") or None

    if not code:
        return jsonify({"success": False, "message": "Coupon code is required"}), 400
    if discount_value <= 0:
        return jsonify({"success": False, "message": "Discount value must be greater than 0"}), 400

    res = add_coupon(
        code=code,
        discount_type=discount_type,
        discount_value=discount_value,
        min_order_amount=min_order_amount,
        max_uses=max_uses,
        expires_at=expires_at,
        is_active=1,
    )
    return jsonify(res)


@app.route("/api/admin/coupon/toggle", methods=["POST"])
def api_admin_toggle_coupon():
    """Toggles active/inactive status of a coupon."""
    if not is_admin_authorized():
        return jsonify({"success": False, "message": "Unauthorized"}), 401
    data = request.get_json(silent=True) or {}
    coupon_id = data.get("coupon_id")
    if not coupon_id:
        return jsonify({"success": False, "message": "Coupon ID is required"}), 400
    ok = toggle_coupon_status(int(coupon_id))
    return jsonify({"success": ok, "message": "Coupon status updated!" if ok else "Coupon not found"})


@app.route("/api/admin/coupon/delete", methods=["POST"])
def api_admin_delete_coupon():
    """Deletes a coupon."""
    if not is_admin_authorized():
        return jsonify({"success": False, "message": "Unauthorized"}), 401
    data = request.get_json(silent=True) or {}
    coupon_id = data.get("coupon_id")
    if not coupon_id:
        return jsonify({"success": False, "message": "Coupon ID is required"}), 400
    ok = delete_coupon(int(coupon_id))
    return jsonify({"success": ok, "message": "Coupon deleted successfully!" if ok else "Coupon not found"})


@app.route("/api/admin/users", methods=["GET"])
def api_admin_users():
    """Returns list of users with wallet balances for admin."""
    if not is_admin_authorized():
        return jsonify({"success": False, "message": "Unauthorized"}), 401
    search = request.args.get("search", "").strip()
    users = get_all_users_with_wallets(search=search, limit=100)
    return jsonify({"success": True, "users": users})


@app.route("/api/admin/user/reset_pin", methods=["POST"])
def api_admin_user_reset_pin():
    """Allows admin to reset any customer's PIN to default (1234) or specified value."""
    if not is_admin_authorized():
        return jsonify({"success": False, "message": "Unauthorized"}), 401
    data = request.get_json(silent=True) or {}
    user_id = data.get("user_id")
    new_pin = str(data.get("new_pin", "1234")).strip()
    if not user_id:
        return jsonify({"success": False, "message": "User ID required"}), 400
    res = admin_reset_user_pin(int(user_id), new_pin)
    return jsonify(res)


@app.route("/api/admin/wallet/adjust", methods=["POST"])
def api_admin_wallet_adjust():
    """Adjusts user wallet balance (add or deduct) with admin authorization."""
    if not is_admin_authorized():
        return jsonify({"success": False, "message": "Unauthorized"}), 401
    data = request.get_json(silent=True) or {}
    user_id = data.get("user_id")
    action = str(data.get("action", "")).lower().strip()
    reason = str(data.get("reason", "")).strip()
    try:
        amount = float(data.get("amount", 0))
    except (ValueError, TypeError):
        return jsonify({"success": False, "message": "Invalid amount"}), 400

    if not user_id:
        return jsonify({"success": False, "message": "User ID is required"}), 400
    if amount <= 0:
        return jsonify({"success": False, "message": "Amount must be greater than 0"}), 400
    if action not in ["add", "deduct"]:
        return jsonify({"success": False, "message": "Action must be 'add' or 'deduct'"}), 400

    res = admin_adjust_wallet(int(user_id), action, amount, reason)
    return jsonify(res)


@app.route("/api/admin/users/<int:user_id>/ledger", methods=["GET"])
def api_admin_user_ledger(user_id):
    """Returns ledger transactions for a user."""
    if not is_admin_authorized():
        return jsonify({"success": False, "message": "Unauthorized"}), 401
    txs = get_wallet_transactions(user_id, limit=30)
    return jsonify({"success": True, "transactions": txs})


@app.errorhandler(500)
@app.errorhandler(Exception)
def handle_internal_server_error(e):
    from werkzeug.exceptions import HTTPException
    if isinstance(e, HTTPException):
        return e

    import traceback
    err_tb = traceback.format_exc()
    logger.error(f"Internal Server Error: {e}\n{err_tb}")
    try:
        with open("crash_route_error.log", "a", encoding="utf-8") as f:
            f.write(f"\n[{datetime.now()}] Route: {request.path}\nError: {e}\n{err_tb}\n")
    except Exception:
        pass

    if request.path.startswith("/api/"):
        return jsonify({
            "success": False,
            "error": "INTERNAL_SERVER_ERROR",
            "message": str(e),
            "traceback": err_tb[:400] if session.get("is_admin") else None,
        }), 500

    return f"""<!DOCTYPE html>
<html>
<head><title>500 - Server Error</title><meta name="viewport" content="width=device-width, initial-scale=1"></head>
<body style="background:#0f172a;color:#f8fafc;font-family:sans-serif;text-align:center;padding:50px 20px;">
    <div style="max-width:550px;margin:0 auto;background:#1e293b;padding:30px;border-radius:16px;border:1px solid rgba(239,68,68,0.3);">
        <div style="font-size:3.5rem;">⚠️</div>
        <h2 style="color:#ef4444;">Server Encountered an Issue</h2>
        <p style="color:#94a3b8;font-size:0.95rem;">{str(e)}</p>
        <pre style="text-align:left;background:#090d16;padding:12px;border-radius:8px;font-size:0.75rem;color:#fca5a5;overflow-x:auto;">{err_tb[:800]}</pre>
        <a href="/" style="display:inline-block;margin-top:15px;padding:10px 20px;background:#38bdf8;color:#000;text-decoration:none;border-radius:8px;font-weight:700;">Refresh Page</a>
    </div>
</body>
</html>""", 500


# =========================================================================
# 🔄 HTG SESSIONS AUTO KEEP-ALIVE DAEMON (Prevents Sessions from Expiring)
# =========================================================================
import threading
import time

def _start_htg_keepalive_worker():
    """Runs a daemon thread to ping HTG every 15 minutes to keep sessions permanently active."""
    def _worker():
        while True:
            try:
                time.sleep(900)  # Ping every 15 minutes
                from htg_engine import load_all_accounts, verify_account_session
                acc_data = load_all_accounts()
                for acc_id, acc in (acc_data.get("accounts") or {}).items():
                    cookies = acc.get("cookies")
                    if cookies and acc.get("enabled", True):
                        verify_account_session(cookies)
            except Exception:
                pass

    t = threading.Thread(target=_worker, daemon=True)
    t.start()


# =========================================================================
# 🔄 AUTOMATED HTG QUEUE RECONCILIATION & AUTO-REFUND ENGINE
# =========================================================================

def auto_reconcile_htg_queue() -> dict:
    """
    Syncs recent HTG history with local orders.
    - If HTG queue_status is 'failed': marks order as 'failed' and AUTO-REFUNDS the customer's wallet!
    - If HTG queue_status is 'done': marks order as 'completed' with real Garena reference ID!
    """
    try:
        from htg_engine import load_session_cookies, DEFAULT_HEADERS
        cookies = load_session_cookies("account_1")
        if not cookies:
            return {"success": False, "message": "No cookies"}

        s = requests.Session()
        s.headers.update(DEFAULT_HEADERS)
        s.cookies.update(cookies)
        if "csrf_token" in cookies:
            s.headers["X-CSRF-Token"] = cookies["csrf_token"]
        s.headers["X-Requested-With"] = "XMLHttpRequest"

        r = s.get("https://htgtopup.com/history.php?action=listTopUp", timeout=10)
        data = r.json() if r.text.startswith("{") else {}
        history = data.get("history", [])

        failed_refunded = []
        completed_synced = []

        for h in history[:35]:
            oid = str(h.get("orderid", "")).strip()
            if not oid:
                continue
            qst = str(h.get("queue_status", "")).lower()
            res_id = str(h.get("result_id", ""))
            pid = str(h.get("playerid", "")).strip()

            order = None
            with get_connection() as conn:
                cursor = conn.cursor()
                cursor.execute(
                    "SELECT * FROM orders WHERE htg_order_ids LIKE ? ORDER BY id DESC LIMIT 1",
                    (f"%{oid}%",),
                )
                r_row = cursor.fetchone()
                if r_row:
                    order = dict(r_row)
                elif pid:
                    # Match recent orders with this player UID
                    cursor.execute(
                        "SELECT * FROM orders WHERE player_id = ? AND status IN ('processing', 'completed', 'payment_submitted') ORDER BY id DESC LIMIT 1",
                        (pid,),
                    )
                    p_row = cursor.fetchone()
                    if p_row:
                        order = dict(p_row)

            if not order:
                continue

            order_code = order["order_code"]

            if qst == "failed":
                ref_res = refund_failed_order(
                    order_code=order_code,
                    reason=f"HTG Queue Failed ({oid}): Garena rejected request for UID {pid}. Wallet auto-refunded."
                )
                with get_connection() as conn:
                    c = conn.cursor()
                    c.execute("UPDATE orders SET htg_order_ids = ? WHERE order_code = ?", (oid, order_code))
                    conn.commit()
                failed_refunded.append({
                    "order_code": order_code,
                    "htg_order_id": oid,
                    "amount": order["amount"],
                    "refunded": ref_res.get("refunded"),
                })
            elif qst == "done":
                if order.get("status") != "completed":
                    full_id = f"{oid} (Ref: {res_id})" if res_id and res_id != "-" else oid
                    mark_order_completed(order_code, full_id)
                    completed_synced.append({
                        "order_code": order_code,
                        "htg_order_id": full_id,
                    })

        return {
            "success": True,
            "failed_refunded": failed_refunded,
            "completed_synced": completed_synced,
            "message": f"Synced {len(completed_synced)} completed and auto-refunded {len(failed_refunded)} failed orders!",
        }
    except Exception as e:
        logger.error(f"Error in auto_reconcile_htg_queue: {e}")
        return {"success": False, "error": str(e)}


@app.route("/api/admin/sync_htg_queue", methods=["GET", "POST"])
def api_admin_sync_htg_queue():
    """Admin endpoint to manually trigger HTG Queue sync & auto-refund."""
    if not is_admin_authorized():
        return jsonify({"success": False, "message": "Unauthorized"}), 401
    res = auto_reconcile_htg_queue()
    return jsonify(res)


def _start_htg_queue_monitor_worker():
    """Runs a daemon thread to monitor and auto-reconcile HTG queue every 5 seconds."""
    def _worker():
        time.sleep(3)
        try:
            auto_reconcile_htg_queue()
        except Exception:
            pass

        while True:
            try:
                time.sleep(5)
                has_active = False
                with get_connection() as conn:
                    cur = conn.cursor()
                    cur.execute("SELECT COUNT(*) as cnt FROM orders WHERE status = 'processing'")
                    row = cur.fetchone()
                    if row and row["cnt"] > 0:
                        has_active = True

                if has_active:
                    auto_reconcile_htg_queue()
            except Exception:
                pass

    t = threading.Thread(target=_worker, daemon=True)
    t.start()


def _start_htg_stock_sync_worker():
    """Runs a daemon thread to periodically sync HTG wholesale rates & stock status every 60s."""
    def _worker():
        time.sleep(10)
        while True:
            try:
                from htg_stock_manager import fetch_live_htg_rates, get_all_products_live_stock
                fetch_live_htg_rates(force=True)
                get_all_products_live_stock(force_refresh=True)
            except Exception:
                pass
            time.sleep(60)

    t = threading.Thread(target=_worker, daemon=True)
    t.start()


# Ensure background daemons run both under WSGI (cPanel Passenger) and local standalone
_bg_workers_started = False
_bg_workers_lock = threading.Lock()

def _ensure_background_workers():
    global _bg_workers_started
    if not _bg_workers_started:
        with _bg_workers_lock:
            if not _bg_workers_started:
                _start_htg_keepalive_worker()
                _start_htg_queue_monitor_worker()
                _start_htg_stock_sync_worker()
                _bg_workers_started = True

try:
    _ensure_background_workers()
except Exception as e:
    logger.warning(f"Could not initialize background workers on import: {e}")


if __name__ == "__main__":
    _ensure_background_workers()
    print(f"🚀 SL CAT TOPUP Web Store running at http://{SERVER_HOST}:{SERVER_PORT}")
    app.run(host=SERVER_HOST, port=SERVER_PORT, debug=False, threaded=True)
