import asyncio
import logging
import sys
import html
import math
import random
from datetime import datetime, timedelta
from typing import Union

# --- Third-party Imports ---
# pip install aiogram aiosqlite httpx
import aiosqlite
import httpx

from aiogram import Bot, Dispatcher, Router, F
from aiogram.client.default import DefaultBotProperties
from aiogram.enums import ParseMode
from aiogram.filters import CommandStart, CommandObject
from aiogram.fsm.context import FSMContext
from aiogram.fsm.state import State, StatesGroup
from aiogram.fsm.storage.memory import MemoryStorage
from aiogram.types import (
    Message, CallbackQuery, InlineKeyboardButton,
    ReplyKeyboardMarkup, KeyboardButton, ReplyKeyboardRemove
)
from aiogram.utils.keyboard import InlineKeyboardBuilder, ReplyKeyboardBuilder
from aiogram.exceptions import TelegramBadRequest

# ==========================================
# 🛠 CONFIGURATION & CONSTANTS
# ==========================================
# ⚠️ توکن و آیدی‌های خود را اینجا جایگزین کنید
BOT_TOKEN = "8572049093:AAGcGCuldOC7129fpmwSLiUdhFH1nU0_wkg"
ADMIN_CHAT_ID = 75096114
RECEIPT_CHANNEL_ID = -1001987654321
DB_NAME = "jewelry.db"

API_KEY = "B4sWF5sHPtMbUmrdqkdlZyYBSkhipfXB"
API_URL = f"https://BrsApi.ir/Api/Market/Gold_Currency.php?key={API_KEY}"
HEADERS = {'User-Agent': 'Mozilla/5.0'}

# زمان انقضای رزرو (۳۰ دقیقه)
RESERVATION_TIMEOUT_MINUTES = 30

# مقادیر پیش‌فرض (دقیقاً طبق فایل اصلی)
DEFAULTS = {
    "card_number": "ثبت نشده",
    "card_owner": "ثبت نشده",
    "address": "تهران، بازار بزرگ، پاساژ طلا، پلاک ۱",
    "admin_phone": "09120000000",
    "instagram_url": "https://instagram.com/gold_shop",
    "profit_percent": "7",
    "deposit_percent": "10",
    "raw_gold_price": "0",
    "shipping_cost": "50000",
    "free_shipping_limit": "10000000"
}

# UI Decoration (دقیقاً طبق فایل اصلی)
HEADER = "💎 <b>G O L D   G A L L E R Y</b> 💎"
DIVIDER = "──────────────"

# تنظیمات لاگ
logging.basicConfig(level=logging.INFO, stream=sys.stdout)
logger = logging.getLogger(__name__)

router = Router()

# ==========================================
# 🗄 DATABASE MANAGER (Async)
# ==========================================


async def init_db():
    """ایجاد جداول دیتابیس"""
    async with aiosqlite.connect(DB_NAME) as db:
        await db.execute("""
            CREATE TABLE IF NOT EXISTS products (
                code TEXT PRIMARY KEY, 
                weight REAL, 
                status TEXT DEFAULT 'available', 
                reserved_at TIMESTAMP, 
                reserved_by INTEGER
            )
        """)
        await db.execute("""
            CREATE TABLE IF NOT EXISTS orders (
                trk TEXT PRIMARY KEY, 
                uid INTEGER, 
                uname TEXT, 
                pcode TEXT, 
                method TEXT, 
                details TEXT, 
                fid TEXT, 
                status TEXT, 
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
            )
        """)
        await db.execute("CREATE TABLE IF NOT EXISTS settings (key TEXT PRIMARY KEY, value TEXT)")

        for k, v in DEFAULTS.items():
            await db.execute("INSERT OR IGNORE INTO settings (key, value) VALUES (?, ?)", (k, v))
        await db.commit()
    logger.info("✅ Database initialized.")


async def db_query(sql, args=(), fetch="one"):
    async with aiosqlite.connect(DB_NAME) as db:
        db.row_factory = aiosqlite.Row
        async with db.execute(sql, args) as cursor:
            if fetch == "one":
                return await cursor.fetchone()
            if fetch == "all":
                return await cursor.fetchall()
            await db.commit()

# --- Helper Functions ---


async def get_setting(key):
    row = await db_query("SELECT value FROM settings WHERE key=?", (key,))
    return row[0] if row else DEFAULTS.get(key, "0")


async def set_setting(key, val):
    await db_query("INSERT OR REPLACE INTO settings (key, value) VALUES (?, ?)", (key, str(val)), fetch="none")


async def db_get_product(code):
    return await db_query("SELECT * FROM products WHERE code=?", (code,), fetch="one")


async def db_get_all_products(admin_view=False):
    if admin_view:
        return await db_query("SELECT * FROM products WHERE status != 'sold' ORDER BY rowid DESC", fetch="all")
    return await db_query("SELECT * FROM products WHERE status='available' ORDER BY rowid DESC", fetch="all")


async def db_add_product(code, weight):
    await db_query("INSERT OR REPLACE INTO products (code, weight, status) VALUES (?, ?, 'available')", (code, weight), fetch="none")


async def db_delete_product(code):
    await db_query("DELETE FROM products WHERE code=?", (code,), fetch="none")


async def db_update_product_status(code, status, user_id=None):
    now = datetime.now() if status == 'reserved' else None
    await db_query("UPDATE products SET status=?, reserved_at=?, reserved_by=? WHERE code=?", (status, now, user_id, code), fetch="none")


async def db_create_order(trk, uid, uname, pcode, method, details, fid):
    await db_query("INSERT INTO orders (trk, uid, uname, pcode, method, details, fid, status) VALUES (?,?,?,?,?,?,?,?)",
                   (trk, uid, uname or "Unknown", pcode, method, details, fid, 'pending'), fetch="none")


async def db_get_order(trk):
    return await db_query("SELECT * FROM orders WHERE trk=?", (trk,), fetch="one")


async def db_update_order_status(trk, status):
    await db_query("UPDATE orders SET status=? WHERE trk=?", (status, trk), fetch="none")


async def db_get_orders_by_status(status):
    return await db_query("SELECT * FROM orders WHERE status=? ORDER BY created_at DESC", (status,), fetch="all")


async def db_get_user_orders(uid):
    return await db_query("SELECT * FROM orders WHERE uid=? ORDER BY created_at DESC", (uid,), fetch="all")


async def db_get_expired_reservations(mins):
    limit = datetime.now() - timedelta(minutes=mins)
    return await db_query("SELECT * FROM products WHERE status='reserved' AND reserved_at < ?", (limit,), fetch="all")

# ==========================================
# 🧠 LOGIC & UTILS
# ==========================================


def is_admin(uid): return uid == ADMIN_CHAT_ID


async def safe_edit_text(call: CallbackQuery, text, reply_markup=None):
    try:
        if call.message.photo:
            await call.message.delete()
            await call.message.answer(text, reply_markup=reply_markup)
        else:
            await call.message.edit_text(text, reply_markup=reply_markup)
    except Exception:
        await call.message.answer(text, reply_markup=reply_markup)


async def fetch_gold_price_logic():
    try:
        async with httpx.AsyncClient(verify=False, timeout=10) as client:
            res = await client.get(API_URL, headers=HEADERS)
        if res.status_code == 200:
            data = res.json().get('gold')
            if data and len(data) > 0:
                p = float(data[0]['price'])
                if p > 0:
                    await set_setting("raw_gold_price", p)
                    return p
    except:
        pass
    return float(await get_setting("raw_gold_price"))


async def calculate_pricing(weight: float) -> dict:
    raw = await fetch_gold_price_logic()
    profit = float(await get_setting("profit_percent"))
    dep_pct = float(await get_setting("deposit_percent"))

    price_gram = raw + (raw * (profit / 100))
    final = price_gram * weight
    deposit = final * (dep_pct / 100)

    return {
        "raw": raw,
        "final": int(final),
        "deposit": int(deposit),
        "profit_pct": profit,
        "deposit_pct": dep_pct
    }


def gen_trk(): return f"TRK-{random.randint(10000, 99999)}"

# ==========================================
# 🚦 STATES
# ==========================================


class FSM(StatesGroup):
    set_val = State()


class AdminStates(StatesGroup):
    waiting_for_code = State()
    waiting_for_weight = State()


class OrderStates(StatesGroup):
    waiting_for_name = State()
    waiting_for_phone = State()
    waiting_for_address = State()
    waiting_for_receipt = State()

# ==========================================
# 🎹 KEYBOARDS (HYBRID - EXACT ORIGINAL TEXTS)
# ==========================================

# --- REPLY KEYBOARDS (دکمه‌های پایین) ---


def kb_main_menu_reply():
    kb = ReplyKeyboardBuilder()
    # متن‌ها دقیقاً طبق فایل اول: "🛍 مشاهده ویترین محصولات"
    kb.row(KeyboardButton(text="🛍 مشاهده ویترین محصولات"))
    kb.row(KeyboardButton(text="📦 سفارشات من"),
           KeyboardButton(text="📞 تماس با ما"))
    return kb.as_markup(resize_keyboard=True)


def kb_admin_menu_reply():
    kb = ReplyKeyboardBuilder()
    # متن‌ها دقیقاً طبق فایل اول
    kb.row(KeyboardButton(text="🛍 مدیریت محصولات"),
           KeyboardButton(text="📦 مدیریت سفارشات"))
    kb.row(KeyboardButton(text="⚙️ تنظیمات فروشگاه"),
           KeyboardButton(text="🔄 آپدیت قیمت"))
    kb.row(KeyboardButton(text="➕ افزودن محصول"))
    return kb.as_markup(resize_keyboard=True)


def kb_cancel_reply():
    kb = ReplyKeyboardBuilder()
    kb.button(text="❌ لغو")  # طبق فایل اول (نه لغو عملیات)
    return kb.as_markup(resize_keyboard=True)

# --- INLINE KEYBOARDS ---


def kb_orders_filter_inline():
    kb = InlineKeyboardBuilder()
    # متن‌ها طبق kb_orders_menu فایل اول
    kb.row(InlineKeyboardButton(text="⏳ در انتظار بررسی",
           callback_data="ls_ord:pending:0"))
    kb.row(InlineKeyboardButton(text="✅ تأیید شده‌ها", callback_data="ls_ord:approved:0"),
           InlineKeyboardButton(text="❌ رد شده‌ها", callback_data="ls_ord:rejected:0"))
    return kb.as_markup()


def kb_admin_settings_inline():
    kb = InlineKeyboardBuilder()
    # متن‌ها طبق kb_admin_settings فایل اول
    kb.row(InlineKeyboardButton(text="👤 صاحب حساب", callback_data="set_owner"),
           InlineKeyboardButton(text="💳 شماره کارت", callback_data="set_card"))
    kb.row(InlineKeyboardButton(text="📞 تماس ادمین", callback_data="set_phone"),
           InlineKeyboardButton(text="📍 آدرس مغازه", callback_data="set_addr"))
    kb.row(InlineKeyboardButton(text="💰 درصد بیعانه", callback_data="set_deposit"),
           InlineKeyboardButton(text="📈 درصد سود", callback_data="set_profit"))
    kb.row(InlineKeyboardButton(text="🛑 سقف ارسال رایگان", callback_data="set_limit"),
           InlineKeyboardButton(text="🚚 هزینه پست", callback_data="set_ship"))
    return kb.as_markup()


def kb_back_to_list_user():
    return InlineKeyboardBuilder().button(text="🔙 بازگشت", callback_data="list_all_user:0").as_markup()


def kb_delivery_method(code):
    kb = InlineKeyboardBuilder()
    # متن‌ها طبق kb_delivery_method فایل اول
    kb.button(text="📍 تحویل حضوری (رزرو)", callback_data=f"pay:{code}:pickup")
    kb.button(text="🚚 ارسال پستی", callback_data=f"pay:{code}:post")
    kb.button(text="❌ لغو", callback_data="cancel_inline")
    kb.adjust(1)
    return kb.as_markup()


def kb_admin_receipt_action(uid, code, trk):
    kb = InlineKeyboardBuilder()
    # متن‌ها طبق kb_admin_receipt_action فایل اول
    kb.button(text="✅ تأیید سفارش", callback_data=f"ok_ord:{trk}")
    kb.button(text="❌ رد سفارش", callback_data=f"no_ord:{trk}")
    return kb.as_markup()


def kb_user_buy_request(code):
    kb = InlineKeyboardBuilder()
    # متن‌ها طبق kb_user_start_request فایل اول
    kb.button(text="🛒 ثبت سفارش / رزرو", callback_data=f"req:{code}")
    kb.button(text="🔙 بازگشت", callback_data="list_all_user:0")
    kb.adjust(1)
    return kb.as_markup()


def kb_admin_approve_reservation(code, user_id):
    kb = InlineKeyboardBuilder()
    # متن‌ها طبق kb_admin_approve_reservation فایل اول
    kb.button(text="✅ تأیید موجودی", callback_data=f"yes:{code}:{user_id}")
    kb.button(text="❌ عدم موجودی", callback_data=f"no:{code}:{user_id}")
    return kb.as_markup()

# ==========================================
# 🎮 HANDLERS (WITH EXACT ORIGINAL TEXTS)
# ==========================================


@router.message(CommandStart())
async def cmd_start(m: Message, command: CommandObject, state: FSMContext):
    await state.clear()

    if command.args:
        await show_product_invoice(m, command.args, from_list=False)
        return

    if is_admin(m.from_user.id):
        # متن اصلی ادمین: "👋 سلام ادمین عزیز!..."
        await m.answer("👋 <b>سلام ادمین عزیز!</b>\nبه پنل مدیریت هوشمند خوش آمدید.", reply_markup=kb_admin_menu_reply())
    else:
        # متن اصلی کاربر: "🌹 به فروشگاه آنلاین طلا و جواهر خوش آمدید..."
        await m.answer("🌹 <b>به فروشگاه آنلاین طلا و جواهر خوش آمدید</b>\n\n💎 مشاهده قیمت لحظه‌ای، خرید آنلاین و پیگیری سفارشات.", reply_markup=kb_main_menu_reply())

# --- لغو عملیات ---


@router.message(F.text == "❌ لغو")
async def cancel_reply(m: Message, state: FSMContext):
    await state.clear()
    kb = kb_admin_menu_reply() if is_admin(m.from_user.id) else kb_main_menu_reply()
    # متن اصلی: "🛑 عملیات لغو شد."
    await m.answer("🛑 عملیات لغو شد.", reply_markup=kb)


@router.callback_query(F.data == "cancel_inline")
async def cancel_inline(c: CallbackQuery, state: FSMContext):
    await state.clear()
    await c.message.delete()
    await c.answer("🛑 عملیات لغو شد.")

# --- منوی کاربر ---


@router.message(F.text == "📞 تماس با ما")
async def menu_contact(m: Message):
    addr = await get_setting("address")
    phone = await get_setting("admin_phone")
    insta = await get_setting("instagram_url")
    # متن اصلی تماس
    text = (
        f"📞 <b>تماس با ما:</b>\n\n"
        f"📍 <b>آدرس:</b> {addr}\n"
        f"📱 <b>تلفن:</b> <code>{phone}</code>\n"
        f"🌐 <a href='{insta}'>اینستاگرام ما</a>"
    )
    await m.answer(text, disable_web_page_preview=True)


@router.message(F.text == "🛍 مشاهده ویترین محصولات")
async def menu_products(m: Message):
    await list_products_logic(m, page=0, is_admin=False)


@router.message(F.text == "📦 سفارشات من")
async def menu_my_orders(m: Message):
    await list_my_orders_logic(m, page=0)

# --- منوی ادمین ---


@router.message(F.text == "🛍 مدیریت محصولات")
async def admin_products(m: Message):
    if not is_admin(m.from_user.id):
        return
    await list_products_logic(m, page=0, is_admin=True)


@router.message(F.text == "📦 مدیریت سفارشات")
async def admin_orders(m: Message):
    if not is_admin(m.from_user.id):
        return
    # متن اصلی مدیریت سفارشات
    await m.answer("📦 <b>مدیریت سفارشات</b>\n\nلطفاً وضعیت مورد نظر را انتخاب کنید:", reply_markup=kb_orders_filter_inline())


@router.message(F.text == "⚙️ تنظیمات فروشگاه")
async def admin_settings(m: Message):
    if not is_admin(m.from_user.id):
        return
    p = await get_setting("profit_percent")
    d = await get_setting("deposit_percent")
    shp = int(float(await get_setting("shipping_cost")))
    lim = int(float(await get_setting("free_shipping_limit")))

    # متن اصلی تنظیمات
    text = (
        f"⚙️ <b>تنظیمات فروشگاه</b>\n\n"
        f"📈 سود: <code>{p}%</code> | 💰 بیعانه: <code>{d}%</code>\n"
        f"🚚 هزینه پست: <code>{shp:,}</code> ت\n"
        f"🛑 سقف ارسال رایگان: <code>{lim:,}</code> ت"
    )
    await m.answer(text, reply_markup=kb_admin_settings_inline())


@router.message(F.text == "🔄 آپدیت قیمت")
async def admin_upd_price(m: Message):
    if not is_admin(m.from_user.id):
        return
    msg = await m.answer("⏳ دریافت قیمت...")
    p = await fetch_gold_price_logic()
    if p:
        # متن اصلی آپدیت
        await msg.edit_text(f"✅ <b>قیمت آپدیت شد!</b>\n💰 قیمت خام جدید: <code>{int(p):,}</code> تومان")
    else:
        await msg.edit_text("❌ خطا در دریافت قیمت!")


@router.message(F.text == "➕ افزودن محصول")
async def admin_add_prod(m: Message, state: FSMContext):
    if not is_admin(m.from_user.id):
        return
    await state.set_state(AdminStates.waiting_for_code)
    # متن اصلی افزودن
    await m.answer("🏷 <b>کد محصول را وارد کنید:</b>", reply_markup=kb_cancel_reply())

# --- منطق لیست‌ها ---


async def list_products_logic(event: Union[Message, CallbackQuery], page: int, is_admin: bool):
    rows = await db_get_all_products(admin_view=is_admin)

    if not rows:
        # متن اصلی خالی
        txt = "📭 لیست خالی است."
        if isinstance(event, Message):
            await event.answer(txt)
        else:
            await event.answer(txt, show_alert=True)
        return

    PER_PAGE = 6
    max_p = math.ceil(len(rows) / PER_PAGE)
    page = max(0, min(page, max_p - 1))

    kb = InlineKeyboardBuilder()
    prefix = "adm_view" if is_admin else "usr_view"

    for p in rows[page*PER_PAGE: (page+1)*PER_PAGE]:
        icon = "🔒 " if p['status'] == 'reserved' else (
            "⏳ " if p['status'] == 'pending_admin' else "📦")
        if is_admin and p['status'] == 'available':
            icon = "🟢 "

        kb.button(text=f"{icon}🏷 {p['code']} | ⚖️ {p['weight']}g",
                  callback_data=f"{prefix}:{p['code']}")

    kb.adjust(1)

    nav = []
    base_cb = "prod_list" if is_admin else "list_all_user"
    if page > 0:
        nav.append(InlineKeyboardButton(text="⬅️ قبلی",
                   callback_data=f"{base_cb}:{page-1}"))
    nav.append(InlineKeyboardButton(
        text=f"📄 {page+1}/{max_p}", callback_data="noop"))
    if page < max_p - 1:
        nav.append(InlineKeyboardButton(text="بعدی ➡️",
                   callback_data=f"{base_cb}:{page+1}"))
    kb.row(*nav)

    # تایتل‌ها دقیقاً طبق فایل اول
    title = "🛍 <b>مدیریت محصولات</b>" if is_admin else "🛍 <b>ویترین محصولات</b>"
    if isinstance(event, Message):
        await event.answer(f"{HEADER}\n\n{title}", reply_markup=kb.as_markup())
    else:
        await safe_edit_text(event, f"{HEADER}\n\n{title}", kb.as_markup())


async def list_my_orders_logic(event: Union[Message, CallbackQuery], page: int):
    uid = event.from_user.id
    rows = await db_get_user_orders(uid)

    if not rows:
        # متن اصلی: "📭 شما هنوز سفارشی ثبت نکرده‌اید."
        txt = "📭 شما هنوز سفارشی ثبت نکرده‌اید."
        if isinstance(event, Message):
            await event.answer(txt)
        else:
            await event.answer(txt, show_alert=True)
        return

    PER = 5
    mx = math.ceil(len(rows)/PER)
    page = max(0, min(page, mx-1))

    kb = InlineKeyboardBuilder()
    emoji_map = {"pending": "⏳", "approved": "✅", "rejected": "❌"}

    for o in rows[page*PER: (page+1)*PER]:
        emoji = emoji_map.get(o['status'], "❓")
        # فرمت دکمه طبق فایل اول
        kb.button(text=f"{emoji} {o['pcode']} | {o['trk']}",
                  callback_data=f"user_ord:{o['trk']}")

    kb.adjust(1)

    nav = []
    if page > 0:
        nav.append(InlineKeyboardButton(text="⬅️ قبلی",
                   callback_data=f"my_ords:{page-1}"))
    if page < mx - 1:
        nav.append(InlineKeyboardButton(text="بعدی ➡️",
                   callback_data=f"my_ords:{page+1}"))
    kb.row(*nav)

    # دکمه بازگشت به منوی اصلی (در اینلاین) - طبق فایل اول
    kb.row(InlineKeyboardButton(
        text="🏠 بازگشت به منوی اصلی", callback_data="user_home"))

    txt = "📦 <b>سفارشات من:</b>"
    if isinstance(event, Message):
        await event.answer(txt, reply_markup=kb.as_markup())
    else:
        await safe_edit_text(event, txt, kb.as_markup())

# --- کالبک‌های لیست ---


@router.callback_query(F.data.startswith("prod_list:") | F.data.startswith("list_all_user:"))
async def cb_list_prod(c: CallbackQuery):
    parts = c.data.split(":")
    is_adm = (parts[0] == "prod_list")
    if is_adm and not is_admin(c.from_user.id):
        return
    await list_products_logic(c, int(parts[1]), is_adm)


@router.callback_query(F.data.startswith("my_ords:"))
async def cb_my_ords(c: CallbackQuery):
    await list_my_orders_logic(c, int(c.data.split(":")[1]))


@router.callback_query(F.data == "user_home")
async def user_home(c: CallbackQuery):
    await c.message.delete()
    await c.message.answer("🌹 <b>منوی اصلی:</b>", reply_markup=kb_main_menu_reply())


@router.callback_query(F.data == "noop")
async def noop(c: CallbackQuery): await c.answer()

# --- تنظیمات (Admin) ---

SETTINGS_MAP = {
    "set_card": ("card_number", "💳 شماره کارت"),
    "set_owner": ("card_owner", "👤 صاحب حساب"),
    "set_addr": ("address", "📍 آدرس مغازه"),
    "set_phone": ("admin_phone", "📞 تماس ادمین"),
    "set_profit": ("profit_percent", "📈 درصد سود"),
    "set_deposit": ("deposit_percent", "💰 درصد بیعانه"),
    "set_ship": ("shipping_cost", "🚚 هزینه پست"),
    "set_limit": ("free_shipping_limit", "🛑 سقف ارسال رایگان")
}


@router.callback_query(F.data.in_(SETTINGS_MAP.keys()))
async def set_start(c: CallbackQuery, state: FSMContext):
    if not is_admin(c.from_user.id):
        return
    key, label = SETTINGS_MAP[c.data]
    await state.update_data(set_key=key, set_label=label)
    await state.set_state(FSM.set_val)
    # متن اصلی درخواست مقدار
    await c.message.answer(f"{label}:", reply_markup=kb_cancel_reply())
    await c.answer()


@router.message(FSM.set_val)
async def set_save(m: Message, state: FSMContext):
    d = await state.get_data()
    await set_setting(d['set_key'], html.escape(m.text))
    # متن اصلی ذخیره: "✅ ... ذخیره شد."
    await m.answer(f"✅ {d['set_label']} ذخیره شد.", reply_markup=kb_admin_menu_reply())
    await state.clear()

# --- مدیریت محصول (Admin) ---


@router.message(AdminStates.waiting_for_code)
async def add_code(m: Message, state: FSMContext):
    await state.update_data(code=html.escape(m.text.strip()))
    await state.set_state(AdminStates.waiting_for_weight)
    # متن اصلی وزن
    await m.answer("⚖️ <b>وزن محصول (گرم):</b>")


@router.message(AdminStates.waiting_for_weight)
async def add_weight(m: Message, state: FSMContext, bot: Bot):
    try:
        w = float(m.text)
        d = await state.get_data()
        await db_add_product(d['code'], w)

        bot_u = await bot.get_me()
        link = f"https://t.me/{bot_u.username}?start={d['code']}"

        # متن اصلی ثبت محصول
        await m.answer(f"✅ <b>محصول ثبت شد!</b>\n\n🔖 کد: <code>{d['code']}</code>\n🔗 لینک: <code>{link}</code>", reply_markup=kb_admin_menu_reply(), disable_web_page_preview=True)
        await state.clear()
    except ValueError:
        await m.answer("❌ فقط عدد وارد کنید.")


@router.callback_query(F.data.startswith("adm_view:"))
async def adm_view_prod(c: CallbackQuery):
    if not is_admin(c.from_user.id):
        return
    code = c.data.split(":")[1]
    p = await db_get_product(code)
    if not p:
        return await c.answer("❌ ناموجود.", show_alert=True)

    status_txt = "✅ موجود" if p['status'] == 'available' else p['status']
    bot_info = await c.bot.get_me()
    link = f"https://t.me/{bot_info.username}?start={code}"

    # متن دقیق جزئیات محصول ادمین
    txt = (
        f"🛍 <b>مدیریت محصول</b>\n\n"
        f"🏷 کد: <code>{code}</code>\n"
        f"⚖️ وزن: <code>{p['weight']}</code>\n"
        f"📊 وضعیت: <b>{status_txt}</b>\n"
        f"🔗 <a href='{link}'>لینک محصول</a>"
    )

    kb = InlineKeyboardBuilder()
    kb.button(text="🗑 حذف", callback_data=f"del:{code}")
    if p['status'] != 'available':
        kb.button(text="🔓 آزاد سازی", callback_data=f"free:{code}")
    kb.button(text="🔙 بازگشت", callback_data="prod_list:0")

    await safe_edit_text(c, txt, kb.adjust(1).as_markup())


@router.callback_query(F.data.startswith("del:"))
async def del_prod(c: CallbackQuery):
    await db_delete_product(c.data.split(":")[1])
    # متن دقیق حذف
    await c.answer("🗑 حذف شد.", show_alert=True)
    await list_products_logic(c, 0, True)


@router.callback_query(F.data.startswith("free:"))
async def free_prod(c: CallbackQuery):
    await db_update_product_status(c.data.split(":")[1], "available")
    await c.answer("آزاد شد")
    await list_products_logic(c, 0, True)

# --- خرید محصول (User) ---


async def show_product_invoice(message_or_call, code: str, from_list=False):
    p = await db_get_product(code)
    if not p or p['status'] == 'sold':
        # متن دقیق ناموجود
        txt = "🚫 <b>این محصول ناموجود است!</b>"
        if isinstance(message_or_call, Message):
            await message_or_call.answer(txt)
        else:
            await safe_edit_text(message_or_call, txt, kb_back_to_list_user())
        return

    pr = await calculate_pricing(p['weight'])
    # متن دقیق فاکتور با اموجی‌ها
    txt = (
        f"💎 <b>جزئیات محصول</b>\n\n"
        f"🔖 کد: <code>{code}</code>\n"
        f"⚖️ وزن: <code>{p['weight']}</code> گرم\n"
        f"📉 نرخ طلا: <code>{int(pr['raw']):,}</code> ت\n"
        f"➕ سود و اجرت: <code>{pr['profit_pct']}%</code>\n"
        f"➖➖➖➖➖➖\n"
        f"💰 <b>قیمت نهایی:</b> 🔥 <code>{pr['final']:,}</code> تومان 🔥"
    )

    kb = kb_user_buy_request(
        code) if p['status'] == 'available' else kb_back_to_list_user()

    if isinstance(message_or_call, Message):
        await message_or_call.answer(txt, reply_markup=kb)
    else:
        await safe_edit_text(message_or_call, txt, kb)


@router.callback_query(F.data.startswith("usr_view:"))
async def user_view_prod(c: CallbackQuery):
    await show_product_invoice(c, c.data.split(":")[1], from_list=True)


@router.callback_query(F.data.startswith("req:"))
async def user_req_buy(c: CallbackQuery, bot: Bot):
    code = c.data.split(":")[1]
    p = await db_get_product(code)
    if p['status'] != 'available':
        return await c.answer("❌ ناموجود.", show_alert=True)

    await db_update_product_status(code, "pending_admin")
    # متن دقیق انتظار
    await safe_edit_text(c, "⏳ <b>درخواست شما برای ادمین ارسال شد.</b>\n\n🔔 به محض تأیید موجودی، دکمه پرداخت برای شما ارسال می‌شود.", kb_back_to_list_user())

    u = c.from_user
    # متن دقیق درخواست برای ادمین
    admin_msg = f"🔔 <b>درخواست خرید جدید</b>\n\n👤 کاربر: {html.escape(u.full_name)} (@{u.username})\n🏷 محصول: <code>{code}</code>\n⚖️ وزن: {p['weight']} گرم"
    await bot.send_message(ADMIN_CHAT_ID, admin_msg, reply_markup=kb_admin_approve_reservation(code, u.id))


@router.callback_query(F.data.startswith("yes:"))
async def adm_yes(c: CallbackQuery, bot: Bot):
    _, code, uid = c.data.split(":")
    await db_update_product_status(code, "reserved", int(uid))
    await safe_edit_text(c, f"✅ <b>محصول {code} برای کاربر رزرو شد.</b>")
    try:
        # متن دقیق تایید موجودی برای کاربر
        msg = f"✅ <b>موجودی محصول {code} تأیید شد!</b>\n\n🚚 <b>روش دریافت سفارش را انتخاب کنید:</b>"
        await bot.send_message(int(uid), msg, reply_markup=kb_delivery_method(code))
    except Exception:
        await c.answer("خطا در ارسال به کاربر", show_alert=True)


@router.callback_query(F.data.startswith("no:"))
async def adm_no(c: CallbackQuery, bot: Bot):
    _, code, uid = c.data.split(":")
    await db_update_product_status(code, "available")
    await safe_edit_text(c, "❌ درخواست رد شد.")
    try:
        await bot.send_message(int(uid), f"❌ <b>درخواست خرید محصول {code} تأیید نشد.</b>")
    except Exception:
        pass

# --- پرداخت ---


@router.callback_query(F.data.startswith("pay:"))
async def pay_start(c: CallbackQuery, state: FSMContext):
    _, code, method = c.data.split(":")

    p = await db_get_product(code)
    if p['status'] != 'reserved' or p['reserved_by'] != c.from_user.id:
        return await c.answer("⚠️ انقضای رزرو.", show_alert=True)

    await state.update_data(order_code=code, method=method)

    if method == "post":
        await state.set_state(OrderStates.waiting_for_name)
        await c.message.delete()
        # متن دقیق دریافت نام
        await c.message.answer("👤 <b>لطفاً نام و نام خانوادگی تحویل گیرنده را وارد کنید:</b>", reply_markup=kb_cancel_reply())
    else:
        await state.update_data(details="تحویل حضوری (رزرو)")
        await gen_invoice(c.message, state)


@router.message(OrderStates.waiting_for_name)
async def ord_name(m: Message, state: FSMContext):
    await state.update_data(n=html.escape(m.text))
    await state.set_state(OrderStates.waiting_for_phone)
    # متن دقیق تلفن
    await m.answer("📞 <b>شماره تماس معتبر:</b>")


@router.message(OrderStates.waiting_for_phone)
async def ord_phone(m: Message, state: FSMContext):
    await state.update_data(p=html.escape(m.text))
    await state.set_state(OrderStates.waiting_for_address)
    # متن دقیق آدرس
    await m.answer("📍 <b>آدرس دقیق پستی و کد پستی:</b>")


@router.message(OrderStates.waiting_for_address)
async def ord_addr(m: Message, state: FSMContext):
    d = await state.get_data()
    det = f"📦 <b>ارسال پستی</b>\n👤 نام: {d['n']}\n📞 تلفن: {d['p']}\n📍 آدرس: {html.escape(m.text)}"
    await state.update_data(details=det)
    await gen_invoice(m, state)


async def gen_invoice(message: Message, state: FSMContext):
    d = await state.get_data()
    p = await db_get_product(d['order_code'])
    pr = await calculate_pricing(p['weight'])

    cost = pr['deposit']
    ship_txt = ""

    if d['method'] == 'post':
        limit = float(await get_setting("free_shipping_limit"))
        s_cost = float(await get_setting("shipping_cost"))
        if pr['final'] >= limit:
            ship_txt = "✅ <b>هزینه پست: رایگان</b> (خرید بالای ۱۰ تومن)"
        else:
            cost += s_cost
            ship_txt = f"🚚 <b>هزینه پست:</b> <code>{int(s_cost):,}</code> تومان"

    card = await get_setting("card_number")
    own = await get_setting("card_owner")

    # متن دقیق فاکتور نهایی پرداخت
    txt = (
        f"💳 <b>فاکتور نهایی پرداخت (مهلت ۳۰ دقیقه)</b>\n"
        f"⚠️ <b>توجه مهم: این مبلغ فقط بیعانه است و قیمت نهایی کالا نیست.</b>\n"
        f"مابقی مبلغ طبق نرخ روز محاسبه می‌شود.\n{DIVIDER}\n"
        f"🏷 محصول: <code>{d['order_code']}</code>\n"
        f"💰 قیمت کل حدودی: <code>{pr['final']:,}</code> تومان\n"
        f"🔹 بیعانه رزرو: <code>{pr['deposit']:,}</code> تومان\n"
        f"{ship_txt}\n"
        f"➖➖➖➖➖➖\n"
        f"🔴 <b>مبلغ قابل پرداخت فعلی:</b>\n"
        f"💸 <b>{int(cost):,} تومان</b>\n\n"
        f"🏦 شماره کارت:\n<code>{card}</code>\n"
        f"👤 به نام: <b>{own}</b>\n\n"
        f"📸 <b>لطفاً پس از واریز مبلغ بیعانه، تصویر فیش را ارسال کنید:</b>"
    )
    await state.set_state(OrderStates.waiting_for_receipt)
    await message.answer(txt, reply_markup=kb_cancel_reply())


@router.message(OrderStates.waiting_for_receipt, F.photo | F.document)
async def ord_receipt(m: Message, state: FSMContext, bot: Bot):
    d = await state.get_data()
    code = d.get('order_code')

    p = await db_get_product(code)
    if not p or p['status'] != 'reserved':
        await m.answer("❌ زمان رزرو تمام شده است.")
        await state.clear()
        return

    fid = m.photo[-1].file_id if m.photo else m.document.file_id
    trk = gen_trk()

    await db_create_order(trk, m.from_user.id, m.from_user.username, code, d['method'], d['details'], fid)
    await db_update_product_status(code, "sold", m.from_user.id)

    try:
        await bot.send_photo(RECEIPT_CHANNEL_ID, fid, caption=f"User: {m.from_user.id} | Code: {code}")
    except:
        pass

    # متن دقیق دریافت فیش
    await m.answer(f"✅ <b>فیش دریافت شد!</b>\n🆔 کد پیگیری شما: <code>{trk}</code>\n⏳ منتظر تأیید ادمین باشید.", reply_markup=kb_main_menu_reply())

    # متن دقیق برای ادمین
    cap = f"📩 <b>سفارش جدید ({'حضوری' if d['method'] == 'pickup' else 'پستی'})</b>\n\n🆔 کد پیگیری: <code>{trk}</code>\n👤 کاربر: @{m.from_user.username}\n🏷 محصول: <code>{code}</code>\n📝 جزئیات:\n{d['details']}"
    await bot.send_photo(ADMIN_CHAT_ID, fid, caption=cap, reply_markup=kb_admin_receipt_action(m.from_user.id, code, trk))
    await state.clear()

# --- مدیریت سفارشات (Admin) ---


@router.callback_query(F.data.startswith("ls_ord"))
async def adm_ls_ord(c: CallbackQuery):
    parts = c.data.split(":")
    status = parts[1]

    if status == 'menu':
        await safe_edit_text(c, "📦 <b>مدیریت سفارشات</b>\n\nلطفاً وضعیت مورد نظر را انتخاب کنید:", kb_orders_filter_inline())
        return

    rows = await db_get_orders_by_status(status)
    if not rows:
        return await c.answer("📭 سفارشی یافت نشد.", show_alert=True)

    kb = InlineKeyboardBuilder()
    emoji = {"pending": "⏳", "approved": "✅", "rejected": "❌"}.get(status, "❓")

    for o in rows[:5]:
        kb.button(text=f"{emoji} {o['trk']} | @{o['uname']}",
                  callback_data=f"adm_ord:{o['trk']}")
    kb.adjust(1)
    kb.button(text="🔙 بازگشت", callback_data="ls_ord:menu")

    filter_name = {"pending": "در انتظار",
                   "approved": "تأیید شده", "rejected": "رد شده"}.get(status)
    await safe_edit_text(c, f"📋 <b>لیست سفارشات ({filter_name})</b>", kb.as_markup())


@router.callback_query(F.data.startswith("adm_ord:"))
async def adm_ord_det(c: CallbackQuery, bot: Bot):
    trk = c.data.split(":")[1]
    o = await db_get_order(trk)
    if not o:
        return await c.answer("یافت نشد")

    mk = kb_admin_receipt_action(o['uid'], o['pcode'], trk)
    # متن دقیق جزئیات سفارش
    cap = (
        f"🧾 <b>جزئیات سفارش</b>\n\n"
        f"🆔 کد پیگیری: <code>{o['trk']}</code>\n"
        f"👤 کاربر: @{o['uname']} (ID: <code>{o['uid']}</code>)\n"
        f"🏷 محصول: <code>{o['pcode']}</code>\n"
        f"🚚 روش: {o['method']}\n"
        f"📊 وضعیت: {o['status']}\n\n"
        f"📝 <b>اطلاعات ثبت شده:</b>\n{o['details']}"
    )

    try:
        await c.message.delete()
        await bot.send_photo(c.from_user.id, o['fid'], caption=cap, reply_markup=mk)
    except:
        pass


@router.callback_query(F.data.startswith("ok_ord:") | F.data.startswith("no_ord:"))
async def adm_decide_ord(c: CallbackQuery, bot: Bot):
    action, trk = c.data.split(":")

    if action == "ok_ord":
        await db_update_order_status(trk, "approved")
        o = await db_get_order(trk)
        addr = await get_setting("address")
        phone = await get_setting("admin_phone")
        insta = await get_setting("instagram_url")

        await safe_edit_text(c, f"✅ <b>سفارش {trk} تأیید شد.</b>", kb_admin_menu_reply())

        # متن تایید برای کاربر
        user_msg = (
            f"🎉 <b>سفارش شما تأیید شد!</b>\n\n"
            f"🆔 کد پیگیری: <code>{trk}</code>\n"
            f"🏷 محصول: <code>{o['pcode']}</code>\n\n"
            f"📣 <b>اطلاعات تماس:</b>\n"
            f"📍 آدرس: {addr}\n"
            f"📞 تلفن: <code>{phone}</code>\n"
            f"📱 <a href='{insta}'>اینستاگرام ما</a>"
        )
        try:
            await bot.send_message(o['uid'], user_msg, disable_web_page_preview=True)
        except:
            pass

    else:  # no_ord
        await db_update_order_status(trk, "rejected")
        o = await db_get_order(trk)
        if o:
            await db_update_product_status(o['pcode'], "available")

        await safe_edit_text(c, f"❌ <b>سفارش {trk} رد شد.</b>", kb_admin_menu_reply())
        try:
            await bot.send_message(o['uid'], f"❌ <b>سفارش {trk} رد شد.</b>\nجهت پیگیری تماس بگیرید.")
        except:
            pass


@router.callback_query(F.data.startswith("user_ord:"))
async def user_ord_det(c: CallbackQuery):
    trk = c.data.split(":")[1]
    o = await db_get_order(trk)
    if not o or o['uid'] != c.from_user.id:
        return await c.answer("Error", show_alert=True)

    emoji_map = {"pending": "⏳ در انتظار",
                 "approved": "✅ تأیید شده", "rejected": "❌ رد شده"}
    status_txt = emoji_map.get(o['status'], "نامشخص")

    txt = (
        f"🧾 <b>جزئیات سفارش</b>\n{DIVIDER}\n"
        f"🆔 کد پیگیری: <code>{o['trk']}</code>\n"
        f"🏷 محصول: <code>{o['pcode']}</code>\n"
        f"📊 وضعیت: <b>{status_txt}</b>\n"
        f"📅 تاریخ: {o['created_at']}\n\n"
        f"📝 جزئیات ثبت شده:\n{o['details']}"
    )
    kb = InlineKeyboardBuilder().button(text="🔙 بازگشت به لیست",
                                        callback_data="my_ords:0").as_markup()
    await safe_edit_text(c, txt, kb)

# ==========================================
# 🚀 LIFECYCLE & STARTUP
# ==========================================


async def on_startup(bot: Bot):
    await init_db()
    asyncio.create_task(background_tasks(bot))
    logger.info("🤖 Bot started!")


async def background_tasks(bot: Bot):
    while True:
        try:
            await fetch_gold_price_logic()
            ex = await db_get_expired_reservations(RESERVATION_TIMEOUT_MINUTES)
            for p in ex:
                await db_update_product_status(p['code'], "available")
                try:
                    # متن دقیق انقضای رزرو
                    await bot.send_message(p['reserved_by'], f"❌ <b>زمان رزرو محصول {p['code']} به پایان رسید.</b>\nمحصول مجدداً در لیست فروش قرار گرفت.")
                except:
                    pass
        except Exception as e:
            logger.error(f"BG Task Error: {e}")

        await asyncio.sleep(60)


async def main():
    bot = Bot(
        token=BOT_TOKEN,
        default=DefaultBotProperties(parse_mode=ParseMode.HTML)
    )

    dp = Dispatcher(storage=MemoryStorage())
    dp.include_router(router)

    dp.startup.register(on_startup)

    await bot.delete_webhook(drop_pending_updates=True)
    logger.info("🚀 Polling started...")
    await dp.start_polling(bot)

if __name__ == "__main__":
    try:
        asyncio.run(main())
    except (KeyboardInterrupt, SystemExit):
        logger.info("👋 Bot stopped.")
