import asyncio, os, sqlite3
from datetime import datetime
from aiogram import Bot, Dispatcher, F, Router
from aiogram.client.default import DefaultBotProperties
from aiogram.enums import ParseMode
from aiogram.filters import CommandStart, Command
from aiogram.fsm.context import FSMContext
from aiogram.fsm.state import State, StatesGroup
from aiogram.types import Message, CallbackQuery, ReplyKeyboardMarkup, KeyboardButton, InlineKeyboardMarkup, InlineKeyboardButton
from aiohttp import web
from aiogram.webhook.aiohttp_server import SimpleRequestHandler, setup_application

TOKEN = os.getenv('BOT_TOKEN', '').strip()
ADMIN_ID = int(os.getenv('ADMIN_ID', '0'))
DB = os.getenv('DB_PATH', 'store.sqlite3')
if not TOKEN or ADMIN_ID <= 0:
    raise RuntimeError('Set BOT_TOKEN and ADMIN_ID environment variables before starting the bot.')

r = Router()
CATS = {'ready_no':'اپل آیدی آماده بدون آیکلود','ready_yes':'اپل آیدی آماده با آیکلود','silver':'اپل آیدی نقره‌ای با آیکلود','gold':'اپل آیدی طلایی با آیکلود'}
WARS = {'ready_no':['30','60','90'],'ready_yes':['30','60','90'],'silver':['60','90','180'],'gold':['180','365','life']}
WL = {'30':'۳۰ روز','60':'۶۰ روز','90':'۹۰ روز','180':'۱۸۰ روز','365':'۳۶۵ روز','life':'مادام‌العمر'}
DEFAULT_PRICES = {('ready_no','30'):50000,('ready_no','60'):70000,('ready_no','90'):90000,('ready_yes','30'):70000,('ready_yes','60'):90000,('ready_yes','90'):110000,('silver','60'):150000,('silver','90'):180000,('silver','180'):240000,('gold','180'):300000,('gold','365'):400000,('gold','life'):550000}

def db():
    c=sqlite3.connect(DB); c.row_factory=sqlite3.Row; return c
def now(): return datetime.now().strftime('%Y-%m-%d %H:%M:%S')
def fmt(n): return f'{int(n):,}'
def is_admin(uid): return uid == ADMIN_ID
def get_user(uid):
    with db() as c: return c.execute('SELECT * FROM users WHERE tg_id=?',(uid,)).fetchone()
def ensure_user(uid):
    with db() as c: c.execute('INSERT OR IGNORE INTO users(tg_id,created_at) VALUES(?,?)',(uid,now()))
def customer_label(uid):
    u=get_user(uid)
    if not u: return f'ID {uid}'
    return f"{u['first_name']} {u['last_name']} | مغازه: {u['store']} | ID: {uid}"
def ik(rows): return InlineKeyboardMarkup(inline_keyboard=rows)
def cat_kb(prefix):
    rows=[[InlineKeyboardButton(text=v,callback_data=f'{prefix}:{k}')] for k,v in CATS.items()]
    rows.append([InlineKeyboardButton(text='🏠 منوی اصلی',callback_data='home')]); return ik(rows)
def home_kb():
    return ReplyKeyboardMarkup(keyboard=[[KeyboardButton(text='🛒 خرید اپل آیدی'),KeyboardButton(text='🛡️ بررسی گارانتی')],[KeyboardButton(text='💰 کیف پول'),KeyboardButton(text='📦 سفارش‌های من')],[KeyboardButton(text='👤 اطلاعات من'),KeyboardButton(text='🎫 پشتیبانی')]],resize_keyboard=True)
def admin_kb():
    return ik([[InlineKeyboardButton(text='📦 موجودی',callback_data='adm:stock'),InlineKeyboardButton(text='➕ افزودن محصول',callback_data='adm:add')],[InlineKeyboardButton(text='💰 قیمت‌ها',callback_data='adm:prices'),InlineKeyboardButton(text='💳 درخواست‌های شارژ',callback_data='adm:topups')],[InlineKeyboardButton(text='📨 پشتیبانی',callback_data='adm:support'),InlineKeyboardButton(text='🛒 سفارش‌ها',callback_data='adm:orders')]])
async def need_active(m):
    u=get_user(m.from_user.id)
    if not u or not u['active']:
        await m.answer('برای فعال‌سازی حساب، /start رو بزن و ثبت‌نام رو کامل کن.'); return False
    return True

class Registration(StatesGroup): first=State(); last=State(); phone=State(); store=State()
class TopUp(StatesGroup): amount=State(); receipt=State()
class Support(StatesGroup): body=State(); reply=State()
class AddProduct(StatesGroup): email=State(); password=State()
class SetPrice(StatesGroup): amount=State()
class ManualOrder(StatesGroup): name=State()
class WarrantyCheck(StatesGroup): account=State()

def init_db():
    with db() as c:
        c.executescript('''
        CREATE TABLE IF NOT EXISTS users(tg_id INTEGER PRIMARY KEY,first_name TEXT DEFAULT '',last_name TEXT DEFAULT '',phone TEXT DEFAULT '',store TEXT DEFAULT '',active INTEGER DEFAULT 0,balance INTEGER DEFAULT 0,created_at TEXT NOT NULL);
        CREATE TABLE IF NOT EXISTS prices(category TEXT,warranty TEXT,amount INTEGER NOT NULL,PRIMARY KEY(category,warranty));
        CREATE TABLE IF NOT EXISTS inventory(id INTEGER PRIMARY KEY AUTOINCREMENT,category TEXT NOT NULL,warranty TEXT NOT NULL,email TEXT NOT NULL,password TEXT NOT NULL,status TEXT DEFAULT 'available',created_at TEXT NOT NULL);
        CREATE TABLE IF NOT EXISTS orders(id INTEGER PRIMARY KEY AUTOINCREMENT,tg_id INTEGER NOT NULL,category TEXT NOT NULL,warranty TEXT NOT NULL,amount INTEGER NOT NULL,status TEXT NOT NULL,customer_name TEXT DEFAULT '',inventory_id INTEGER,created_at TEXT NOT NULL);
        CREATE TABLE IF NOT EXISTS topups(id INTEGER PRIMARY KEY AUTOINCREMENT,tg_id INTEGER NOT NULL,amount INTEGER NOT NULL,receipt TEXT NOT NULL,status TEXT DEFAULT 'pending',created_at TEXT NOT NULL);
        CREATE TABLE IF NOT EXISTS support(id INTEGER PRIMARY KEY AUTOINCREMENT,tg_id INTEGER NOT NULL,body TEXT NOT NULL,reply TEXT DEFAULT '',status TEXT DEFAULT 'pending',created_at TEXT NOT NULL,replied_at TEXT DEFAULT '');
        CREATE TABLE IF NOT EXISTS warranty_checks(id INTEGER PRIMARY KEY AUTOINCREMENT,tg_id INTEGER NOT NULL,category TEXT NOT NULL,account TEXT NOT NULL,created_at TEXT NOT NULL);
        ''')
        for (cat,w),amount in DEFAULT_PRICES.items(): c.execute('INSERT OR IGNORE INTO prices VALUES(?,?,?)',(cat,w,amount))

@r.message(CommandStart())
async def start(m:Message,state:FSMContext):
    ensure_user(m.from_user.id); u=get_user(m.from_user.id)
    if u['active']:
        await state.clear(); await m.answer(f"سلام {u['first_name']}! 🍎 به فروشگاه خوش اومدی.\nموجودی: {fmt(u['balance'])} تومان",reply_markup=home_kb()); return
    await state.clear(); await state.set_state(Registration.first); await m.answer('سلام! برای فعال شدن حساب، ثبت‌نام اولیه رو انجام بده.\n\nنامت رو وارد کن:')
@r.message(Registration.first)
async def reg_first(m:Message,state:FSMContext):
    v=(m.text or '').strip()
    if len(v)<2: await m.answer('نام معتبر وارد کن:'); return
    await state.update_data(first=v); await state.set_state(Registration.last); await m.answer('نام خانوادگی رو وارد کن:')
@r.message(Registration.last)
async def reg_last(m:Message,state:FSMContext):
    v=(m.text or '').strip()
    if len(v)<2: await m.answer('نام خانوادگی معتبر وارد کن:'); return
    await state.update_data(last=v); await state.set_state(Registration.phone)
    await m.answer('شماره تلفنت رو با دکمه زیر به اشتراک بذار:',reply_markup=ReplyKeyboardMarkup(keyboard=[[KeyboardButton(text='📱 اشتراک‌گذاری شماره تلفن',request_contact=True)]],resize_keyboard=True,one_time_keyboard=True))
@r.message(Registration.phone)
async def reg_phone(m:Message,state:FSMContext):
    if not m.contact or m.contact.user_id != m.from_user.id:
        await m.answer('لطفاً شماره متعلق به حساب خودت رو با دکمه اشتراک‌گذاری ارسال کن.'); return
    await state.update_data(phone=m.contact.phone_number); await state.set_state(Registration.store); await m.answer('نام مغازه یا فروشگاهت رو وارد کن:')
@r.message(Registration.store)
async def reg_store(m:Message,state:FSMContext):
    store=(m.text or '').strip()
    if len(store)<2: await m.answer('نام مغازه معتبر وارد کن:'); return
    d=await state.get_data()
    with db() as c: c.execute('UPDATE users SET first_name=?,last_name=?,phone=?,store=?,active=1 WHERE tg_id=?',(d['first'],d['last'],d['phone'],store,m.from_user.id))
    await state.clear(); await m.answer('✅ ثبت‌نام تکمیل شد و حساب فعال شد.',reply_markup=home_kb()); await m.answer(f"سلام {d['first']}! 🍎\nموجودی کیف پول: 0 تومان",reply_markup=home_kb())
    try: await m.bot.send_message(ADMIN_ID,'🆕 ثبت‌نام جدید:\n'+customer_label(m.from_user.id))
    except Exception: pass

@r.message(Command('admin'))
async def admin_cmd(m:Message):
    if is_admin(m.from_user.id): await m.answer('⚙️ پنل مدیریت',reply_markup=admin_kb())
    else: await m.answer('این دستور فقط برای مدیر فعاله.')
@r.message(F.text=='🛒 خرید اپل آیدی')
async def shop(m:Message):
    if await need_active(m): await m.answer('دسته‌بندی محصول رو انتخاب کن:',reply_markup=cat_kb('buy'))
@r.callback_query(F.data.startswith('buy:'))
async def buy_category(q:CallbackQuery):
    key=q.data.split(':')[1]
    rows=[[InlineKeyboardButton(text='گارانتی '+WL[w],callback_data=f'choose:{key}:{w}')] for w in WARS[key]]
    rows.append([InlineKeyboardButton(text='🔙 دسته‌ها',callback_data='shopback')])
    await q.message.answer(CATS[key]+'\nمدت گارانتی رو انتخاب کن:',reply_markup=ik(rows)); await q.answer()
@r.callback_query(F.data=='shopback')
async def shop_back(q:CallbackQuery): await q.message.answer('دسته‌بندی رو انتخاب کن:',reply_markup=cat_kb('buy')); await q.answer()
@r.callback_query(F.data.startswith('choose:'))
async def choose_warranty(q:CallbackQuery):
    _,cat,w=q.data.split(':')
    with db() as c:
        p=c.execute('SELECT amount FROM prices WHERE category=? AND warranty=?',(cat,w)).fetchone()
        n=c.execute("SELECT COUNT(*) n FROM inventory WHERE category=? AND warranty=? AND status='available'",(cat,w)).fetchone()['n']
    if not p: await q.answer('قیمت تنظیم نشده.',show_alert=True); return
    text=f"محصول: {CATS[cat]}\nگارانتی: {WL[w]}\nقیمت: {fmt(p['amount'])} تومان\n"
    if cat.startswith('ready'): text+=f'موجودی: {n} عدد'; action=f'buyit:{cat}:{w}'; label='✅ خرید'
    else: text+='این محصول به‌صورت سفارش دستی ثبت می‌شه.'; action=f'manual:{cat}:{w}'; label='✅ ثبت سفارش'
    await q.message.answer(text,reply_markup=ik([[InlineKeyboardButton(text=label,callback_data=action)],[InlineKeyboardButton(text='🔙 دسته‌ها',callback_data='shopback')]])); await q.answer()
@r.callback_query(F.data.startswith('buyit:'))
async def buy_ready(q:CallbackQuery):
    _,cat,w=q.data.split(':')
    with db() as c:
        u=c.execute('SELECT * FROM users WHERE tg_id=? AND active=1',(q.from_user.id,)).fetchone(); p=c.execute('SELECT amount FROM prices WHERE category=? AND warranty=?',(cat,w)).fetchone(); item=c.execute("SELECT * FROM inventory WHERE category=? AND warranty=? AND status='available' ORDER BY id LIMIT 1",(cat,w)).fetchone()
        if not u: await q.answer('اول ثبت‌نام کن.',show_alert=True); return
        if not p or not item: await q.answer('محصول فعلاً موجود نیست.',show_alert=True); return
        if u['balance']<p['amount']: await q.message.answer('موجودی کافی نیست؛ از کیف پول درخواست شارژ ثبت کن.'); await q.answer(); return
        c.execute('UPDATE users SET balance=balance-? WHERE tg_id=?',(p['amount'],q.from_user.id)); c.execute("UPDATE inventory SET status='sold' WHERE id=?",(item['id'],))
        oid=c.execute('INSERT INTO orders(tg_id,category,warranty,amount,status,inventory_id,created_at) VALUES(?,?,?,?,?,?,?)',(q.from_user.id,cat,w,p['amount'],'delivered',item['id'],now())).lastrowid
    await q.message.answer(f"✅ خرید موفق — سفارش #{oid}\nمحصول: {CATS[cat]}\nگارانتی: {WL[w]}\nمبلغ: {fmt(p['amount'])} تومان\n\nایمیل/یوزر: <code>{item['email']}</code>\nرمز عبور: <code>{item['password']}</code>",reply_markup=home_kb()); await q.answer('خرید انجام شد.')
@r.callback_query(F.data.startswith('manual:'))
async def manual_start(q:CallbackQuery,state:FSMContext):
    _,cat,w=q.data.split(':'); await state.update_data(cat=cat,w=w); await state.set_state(ManualOrder.name); await q.message.answer('نام و نام خانوادگی سفارش‌گیرنده رو وارد کن:'); await q.answer()
@r.message(ManualOrder.name)
async def manual_finish(m:Message,state:FSMContext):
    name=(m.text or '').strip(); d=await state.get_data()
    if len(name)<3: await m.answer('نام و نام خانوادگی معتبر وارد کن:'); return
    with db() as c:
        u=c.execute('SELECT balance FROM users WHERE tg_id=? AND active=1',(m.from_user.id,)).fetchone(); p=c.execute('SELECT amount FROM prices WHERE category=? AND warranty=?',(d['cat'],d['w'])).fetchone()
        if not u or not p: await state.clear(); await m.answer('حساب یا قیمت پیدا نشد.'); return
        if u['balance']<p['amount']: await state.clear(); await m.answer('موجودی کافی نیست؛ اول کیف پول رو شارژ کن.',reply_markup=home_kb()); return
        oid=c.execute('INSERT INTO orders(tg_id,category,warranty,amount,status,customer_name,created_at) VALUES(?,?,?,?,?,?,?)',(m.from_user.id,d['cat'],d['w'],p['amount'],'pending',name,now())).lastrowid
        c.execute('UPDATE users SET balance=balance-? WHERE tg_id=?',(p['amount'],m.from_user.id))
    await state.clear(); await m.answer(f'سفارش دستی #{oid} ثبت شد و برای مدیر ارسال شد.',reply_markup=home_kb())
    await m.bot.send_message(ADMIN_ID,f"🛒 سفارش دستی #{oid}\n{customer_label(m.from_user.id)}\nمحصول: {CATS[d['cat']]}\nگارانتی: {WL[d['w']]}\nنام سفارش‌گیرنده: {name}\nمبلغ: {fmt(p['amount'])} تومان")

@r.message(F.text=='💰 کیف پول')
async def wallet(m:Message):
    if not await need_active(m): return
    u=get_user(m.from_user.id); await m.answer(f"💰 موجودی کیف پول: {fmt(u['balance'])} تومان",reply_markup=ik([[InlineKeyboardButton(text='➕ درخواست شارژ',callback_data='topup:start')],[InlineKeyboardButton(text='📋 تراکنش‌ها',callback_data='transactions')]]))
@r.callback_query(F.data=='topup:start')
async def topup_start(q:CallbackQuery,state:FSMContext): await state.set_state(TopUp.amount); await q.message.answer('مبلغ شارژ رو به تومان وارد کن (۳۰۰٬۰۰۰ تا ۵٬۰۰۰٬۰۰۰):'); await q.answer()
@r.message(TopUp.amount)
async def topup_amount(m:Message,state:FSMContext):
    try: amount=int((m.text or '').replace(',','').replace('٬','').replace(' ','').replace('،',''))
    except ValueError: await m.answer('مبلغ رو فقط به عدد وارد کن:'); return
    if not 300000<=amount<=5000000: await m.answer('مبلغ باید بین ۳۰۰٬۰۰۰ تا ۵٬۰۰۰٬۰۰۰ تومان باشه:'); return
    await state.update_data(amount=amount); await state.set_state(TopUp.receipt); await m.answer('عکس رسید پرداخت رو ارسال کن:')
@r.message(TopUp.receipt,F.photo)
async def topup_receipt(m:Message,state:FSMContext):
    d=await state.get_data(); fid=m.photo[-1].file_id
    with db() as c: tid=c.execute('INSERT INTO topups(tg_id,amount,receipt,created_at) VALUES(?,?,?,?)',(m.from_user.id,d['amount'],fid,now())).lastrowid
    await state.clear(); await m.answer(f'درخواست شارژ #{tid} ثبت شد و منتظر بررسی مدیر است.',reply_markup=home_kb())
    u=get_user(m.from_user.id); cap=f"💳 درخواست شارژ #{tid}\nنام: {u['first_name']} {u['last_name']}\nشناسه: {m.from_user.id}\nمغازه: {u['store']}\nشماره: {u['phone']}\nمبلغ: {fmt(d['amount'])} تومان\nزمان: {now()}"
    await m.bot.send_photo(ADMIN_ID,fid,caption=cap,reply_markup=ik([[InlineKeyboardButton(text='✅ تأیید شارژ',callback_data=f'topup:approve:{tid}')],[InlineKeyboardButton(text='❌ رد تراکنش',callback_data=f'topup:reject:{tid}')]]))
@r.message(TopUp.receipt)
async def topup_need_photo(m:Message): await m.answer('لطفاً رسید رو به‌صورت عکس ارسال کن.')
@r.callback_query(F.data.startswith('topup:'))
async def topup_review(q:CallbackQuery):
    if not is_admin(q.from_user.id): await q.answer('دسترسی ندارید.',show_alert=True); return
    _,action,raw=q.data.split(':'); tid=int(raw)
    with db() as c:
        row=c.execute('SELECT * FROM topups WHERE id=?',(tid,)).fetchone()
        if not row: await q.answer('درخواست پیدا نشد.',show_alert=True); return
        if row['status']!='pending': await q.answer('قبلاً بررسی شده.',show_alert=True); return
        if action=='approve':
            c.execute("UPDATE topups SET status='approved' WHERE id=?",(tid,)); c.execute('UPDATE users SET balance=balance+? WHERE tg_id=?',(row['amount'],row['tg_id'])); bal=c.execute('SELECT balance FROM users WHERE tg_id=?',(row['tg_id'],)).fetchone()['balance']
        else: c.execute("UPDATE topups SET status='rejected' WHERE id=?",(tid,)); bal=0
    if action=='approve': await q.bot.send_message(row['tg_id'],'افزایش موجودی با موفقیت تأیید شد'); await q.message.answer(f'شارژ #{tid} تأیید شد. موجودی جدید: {fmt(bal)} تومان')
    else: await q.bot.send_message(row['tg_id'],'تراکنش نامعتبر می‌باشد'); await q.message.answer(f'شارژ #{tid} رد شد.')
    await q.answer()
@r.callback_query(F.data=='transactions')
async def transactions(q:CallbackQuery):
    with db() as c:
        ts=c.execute('SELECT * FROM topups WHERE tg_id=? ORDER BY id DESC LIMIT 10',(q.from_user.id,)).fetchall(); orders=c.execute('SELECT * FROM orders WHERE tg_id=? ORDER BY id DESC LIMIT 10',(q.from_user.id,)).fetchall()
    lines=[f"شارژ #{x['id']}: {fmt(x['amount'])} تومان — {x['status']}" for x in ts]+[f"سفارش #{x['id']}: {fmt(x['amount'])} تومان — {x['status']}" for x in orders]
    await q.message.answer('📋 تراکنش‌های اخیر\n\n'+'\n'.join(lines) if lines else 'تراکنشی ثبت نشده.'); await q.answer()

@r.message(F.text=='📦 سفارش‌های من')
async def my_orders(m:Message):
    if not await need_active(m): return
    with db() as c: rows=c.execute('SELECT * FROM orders WHERE tg_id=? ORDER BY id DESC LIMIT 20',(m.from_user.id,)).fetchall()
    if not rows: await m.answer('هنوز سفارشی ثبت نکردی.'); return
    await m.answer('\n\n'.join(f"سفارش #{x['id']} — {CATS[x['category']]}\nگارانتی: {WL[x['warranty']]}\nمبلغ: {fmt(x['amount'])} تومان\nوضعیت: {x['status']}" for x in rows))
@r.message(F.text=='👤 اطلاعات من')
async def profile(m:Message):
    if not await need_active(m): return
    u=get_user(m.from_user.id); await m.answer(f"👤 اطلاعات حساب\nنام: {u['first_name']} {u['last_name']}\nشماره: {u['phone']}\nمغازه: {u['store']}\nشناسه تلگرام: {u['tg_id']}\nموجودی: {fmt(u['balance'])} تومان")

@r.message(F.text=='🎫 پشتیبانی')
async def support_start(m:Message,state:FSMContext):
    if await need_active(m): await state.set_state(Support.body); await m.answer('متن کامل پیام یا مشکلت رو در یک پیام بنویس و ارسال کن:')
@r.message(Support.body)
async def support_submit(m:Message,state:FSMContext):
    body=(m.text or m.caption or '').strip()
    if len(body)<2: await m.answer('لطفاً متن پیام رو بنویس:'); return
    with db() as c: sid=c.execute('INSERT INTO support(tg_id,body,created_at) VALUES(?,?,?)',(m.from_user.id,body,now())).lastrowid
    await state.clear(); await m.answer(f'پیام پشتیبانی #{sid} ثبت شد. پاسخ مدیر در همین ربات برات ارسال می‌شه.',reply_markup=home_kb())
    u=get_user(m.from_user.id); await m.bot.send_message(ADMIN_ID,f"📨 پیام پشتیبانی #{sid}\n{u['first_name']} {u['last_name']}\nشناسه: {m.from_user.id}\nمغازه: {u['store']}\nشماره: {u['phone']}\nزمان: {now()}\n\nمتن کامل:\n{body}",reply_markup=ik([[InlineKeyboardButton(text='✍️ پاسخ به همین پیام',callback_data=f'support:reply:{sid}')]]))
@r.callback_query(F.data.startswith('support:reply:'))
async def support_reply_start(q:CallbackQuery,state:FSMContext):
    if not is_admin(q.from_user.id): await q.answer('دسترسی ندارید.',show_alert=True); return
    sid=int(q.data.split(':')[2])
    with db() as c: row=c.execute('SELECT * FROM support WHERE id=?',(sid,)).fetchone()
    if not row: await q.answer('پیام پیدا نشد.',show_alert=True); return
    await state.set_state(Support.reply); await state.update_data(sid=sid); await q.message.answer(f"پاسخ به پیام #{sid} از {customer_label(row['tg_id'])}\n\nمتن پیام:\n{row['body']}\n\nپاسخت رو در یک پیام بفرست:"); await q.answer()
@r.message(Support.reply)
async def support_reply_send(m:Message,state:FSMContext):
    if not is_admin(m.from_user.id): await state.clear(); return
    body=(m.text or '').strip()
    if not body: await m.answer('پاسخ خالیه؛ متن پاسخ رو بنویس:'); return
    d=await state.get_data()
    with db() as c:
        row=c.execute('SELECT * FROM support WHERE id=?',(d['sid'],)).fetchone()
        if not row: await state.clear(); await m.answer('پیام پیدا نشد.'); return
        c.execute("UPDATE support SET reply=?,status='answered',replied_at=? WHERE id=?",(body,now(),d['sid']))
    await m.bot.send_message(row['tg_id'],f"💬 پاسخ پشتیبانی به پیام #{d['sid']}:\n\n{body}"); await state.clear(); await m.answer(f'✅ پاسخ پیام #{d["sid"]} برای همان کاربر ارسال شد.')

@r.message(F.text=='🛡️ بررسی گارانتی')
async def warranty_start(m:Message):
    if await need_active(m): await m.answer('نوع محصول رو انتخاب کن:',reply_markup=cat_kb('check'))
@r.callback_query(F.data.startswith('check:'))
async def warranty_cat(q:CallbackQuery,state:FSMContext):
    cat=q.data.split(':')[1]; await state.update_data(check_cat=cat); await state.set_state(WarrantyCheck.account); await q.message.answer('یوزر/ایمیل اپل آیدی رو برای ثبت درخواست بررسی ارسال کن:'); await q.answer()
@r.message(WarrantyCheck.account)
async def warranty_submit(m:Message,state:FSMContext):
    account=(m.text or '').strip(); d=await state.get_data()
    if len(account)<2: await m.answer('یوزر معتبر وارد کن:'); return
    with db() as c: cid=c.execute('INSERT INTO warranty_checks(tg_id,category,account,created_at) VALUES(?,?,?,?)',(m.from_user.id,d['check_cat'],account,now())).lastrowid
    await state.clear(); await m.answer(f'درخواست بررسی گارانتی #{cid} برای مدیر ارسال شد.',reply_markup=home_kb()); await m.bot.send_message(ADMIN_ID,f"🛡️ بررسی گارانتی #{cid}\n{customer_label(m.from_user.id)}\nمحصول: {CATS[d['check_cat']]}\nیوزر: {account}")

@r.callback_query(F.data.startswith('adm:'))
async def admin_actions(q:CallbackQuery,state:FSMContext):
    if not is_admin(q.from_user.id): await q.answer('دسترسی ندارید.',show_alert=True); return
    action=q.data.split(':')[1]
    if action=='stock':
        with db() as c: rows=c.execute("SELECT category,warranty,COUNT(*) n FROM inventory WHERE status='available' GROUP BY category,warranty").fetchall()
        counts={(x['category'],x['warranty']):x['n'] for x in rows}; lines=['📦 موجودی قابل فروش']
        for cat in CATS:
            for w in WARS[cat]: lines.append(f"{CATS[cat]} — {WL[w]}: {counts.get((cat,w),0)}")
        await q.message.answer('\n'.join(lines),reply_markup=admin_kb())
    elif action=='add': await state.set_state(AddProduct.email); await state.update_data(stage='choose'); await q.message.answer('برای افزودن موجودی، دسته را انتخاب کن:',reply_markup=cat_kb('invcat'))
    elif action=='prices': await q.message.answer('دسته محصول را انتخاب کن:',reply_markup=cat_kb('pricecat'))
    elif action=='topups':
        with db() as c: rows=c.execute('SELECT * FROM topups ORDER BY id DESC LIMIT 20').fetchall()
        await q.message.answer('💳 درخواست‌های شارژ:\n\n'+'\n\n'.join(f"#{x['id']} · {customer_label(x['tg_id'])}\nمبلغ: {fmt(x['amount'])} تومان\nوضعیت: {x['status']}" for x in rows) if rows else 'درخواست شارژی ثبت نشده.',reply_markup=admin_kb())
        for x in rows:
            if x['status']=='pending': await q.bot.send_photo(ADMIN_ID,x['receipt'],caption=f"رسید شارژ #{x['id']} — {fmt(x['amount'])} تومان",reply_markup=ik([[InlineKeyboardButton(text='✅ تأیید',callback_data=f"topup:approve:{x['id']}"),InlineKeyboardButton(text='❌ رد',callback_data=f"topup:reject:{x['id']}")]]))
    elif action=='support':
        with db() as c: rows=c.execute('SELECT * FROM support ORDER BY id DESC LIMIT 25').fetchall()
        if not rows: await q.message.answer('پیام پشتیبانی ثبت نشده.',reply_markup=admin_kb())
        else:
            for x in rows: await q.message.answer(f"📨 پیام #{x['id']} — {customer_label(x['tg_id'])}\nوضعیت: {x['status']}\nزمان: {x['created_at']}\n\n{x['body']}"+(f"\n\nپاسخ قبلی: {x['reply']}" if x['reply'] else ''),reply_markup=ik([[InlineKeyboardButton(text='✍️ پاسخ',callback_data=f"support:reply:{x['id']}")]]))
    elif action=='orders':
        with db() as c: rows=c.execute('SELECT * FROM orders ORDER BY id DESC LIMIT 25').fetchall()
        await q.message.answer('🛒 سفارش‌های اخیر:\n\n'+'\n\n'.join(f"#{x['id']} · {customer_label(x['tg_id'])}\n{CATS[x['category']]}\nگارانتی: {WL[x['warranty']]}\nمبلغ: {fmt(x['amount'])}\nوضعیت: {x['status']}" for x in rows) if rows else 'سفارشی ثبت نشده.',reply_markup=admin_kb())
    await q.answer()

@r.callback_query(F.data.startswith('invcat:'))
async def inventory_cat(q:CallbackQuery,state:FSMContext):
    if not is_admin(q.from_user.id): await q.answer('دسترسی ندارید.',show_alert=True); return
    cat=q.data.split(':')[1]; await state.update_data(inv_cat=cat); await q.message.answer('مدت گارانتی رو انتخاب کن:',reply_markup=ik([[InlineKeyboardButton(text=WL[w],callback_data=f'invw:{w}')] for w in WARS[cat]])); await q.answer()
@r.callback_query(F.data.startswith('invw:'))
async def inventory_war(q:CallbackQuery,state:FSMContext):
    if not is_admin(q.from_user.id): await q.answer('دسترسی ندارید.',show_alert=True); return
    await state.update_data(inv_war=q.data.split(':')[1]); await state.set_state(AddProduct.email); await q.message.answer('یوزر/ایمیل حسابی که مجاز به واگذاری آن هستی رو وارد کن:'); await q.answer()
@r.message(AddProduct.email)
async def inventory_email(m:Message,state:FSMContext):
    if not is_admin(m.from_user.id): await state.clear(); return
    d=await state.get_data()
    if 'inv_cat' not in d or 'inv_war' not in d:
        await m.answer('ابتدا از /admin وارد پنل شو و افزودن محصول را انتخاب کن.',reply_markup=admin_kb()); await state.clear(); return
    email=(m.text or '').strip()
    if len(email)<3: await m.answer('یوزر/ایمیل معتبر وارد کن:'); return
    await state.update_data(inv_email=email); await state.set_state(AddProduct.password); await m.answer('رمز عبور حساب مجاز به واگذاری رو وارد کن:')
@r.message(AddProduct.password)
async def inventory_password(m:Message,state:FSMContext):
    if not is_admin(m.from_user.id): await state.clear(); return
    pw=(m.text or '').strip(); d=await state.get_data()
    if not pw: await m.answer('رمز عبور رو وارد کن:'); return
    with db() as c: c.execute('INSERT INTO inventory(category,warranty,email,password,created_at) VALUES(?,?,?,?,?)',(d['inv_cat'],d['inv_war'],d['inv_email'],pw,now()))
    await state.clear(); await m.answer('✅ محصول به موجودی اضافه شد.',reply_markup=admin_kb())
@r.callback_query(F.data.startswith('pricecat:'))
async def price_cat(q:CallbackQuery,state:FSMContext):
    if not is_admin(q.from_user.id): await q.answer('دسترسی ندارید.',show_alert=True); return
    cat=q.data.split(':')[1]; await state.update_data(price_cat=cat); await q.message.answer('مدت گارانتی:',reply_markup=ik([[InlineKeyboardButton(text=WL[w],callback_data=f'pricew:{w}')] for w in WARS[cat]])); await q.answer()
@r.callback_query(F.data.startswith('pricew:'))
async def price_war(q:CallbackQuery,state:FSMContext):
    if not is_admin(q.from_user.id): await q.answer('دسترسی ندارید.',show_alert=True); return
    await state.update_data(price_war=q.data.split(':')[1]); await state.set_state(SetPrice.amount); await q.message.answer('قیمت جدید رو به تومان وارد کن:'); await q.answer()
@r.message(SetPrice.amount)
async def price_save(m:Message,state:FSMContext):
    if not is_admin(m.from_user.id): await state.clear(); return
    try: amount=int((m.text or '').replace(',','').replace('٬','').replace(' ',''))
    except ValueError: await m.answer('قیمت رو فقط به عدد وارد کن:'); return
    if amount<0: await m.answer('قیمت معتبر وارد کن:'); return
    d=await state.get_data()
    with db() as c: c.execute('INSERT INTO prices VALUES(?,?,?) ON CONFLICT(category,warranty) DO UPDATE SET amount=excluded.amount',(d['price_cat'],d['price_war'],amount))
    await state.clear(); await m.answer('✅ قیمت به‌روزرسانی شد.',reply_markup=admin_kb())
@r.callback_query(F.data=='home')
async def go_home(q:CallbackQuery,state:FSMContext):
    await state.clear(); u=get_user(q.from_user.id)
    if not u or not u['active']: await q.message.answer('برای فعال‌سازی، /start رو بزن.')
    else: await q.message.answer(f"سلام {u['first_name']}! 🍎 موجودی: {fmt(u['balance'])} تومان",reply_markup=home_kb())
    await q.answer()

async def main():
    init_db()
    bot=Bot(TOKEN,default=DefaultBotProperties(parse_mode=ParseMode.HTML))
    dp=Dispatcher()
    dp.include_router(r)

    # If WEBHOOK_HOST is configured, run as a webhook server; otherwise use polling.
    webhook_host=os.getenv('WEBHOOK_HOST','').strip().rstrip('/')
    if webhook_host:
        from urllib.parse import urlparse
        parsed=urlparse(webhook_host)
        if parsed.scheme != 'https' or not parsed.netloc or parsed.path:
            raise RuntimeError('WEBHOOK_HOST must be a public HTTPS base URL, e.g. https://bot.example.com (no path or trailing slash).')
        webhook_path='/' + os.getenv('WEBHOOK_PATH','telegram/webhook').strip('/')
        webhook_secret=os.getenv('WEBHOOK_SECRET','').strip()
        webhook_port=int(os.getenv('WEBHOOK_PORT','8080'))
        if not (1 <= len(webhook_secret) <= 256) or not all(ch in 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-' for ch in webhook_secret):
            raise RuntimeError('WEBHOOK_SECRET must be 1-256 characters using only letters, numbers, underscore, or hyphen.')
        if not (1 <= webhook_port <= 65535):
            raise RuntimeError('WEBHOOK_PORT must be between 1 and 65535.')
        app=web.Application()
        async def health(_request):
            return web.json_response({'status':'ok'})
        app.router.add_get('/health',health)
        SimpleRequestHandler(dispatcher=dp,bot=bot,secret_token=webhook_secret).register(app,path=webhook_path)
        setup_application(app,dp,bot=bot)
        webhook_url=webhook_host+webhook_path
        await bot.set_webhook(url=webhook_url,secret_token=webhook_secret,allowed_updates=dp.resolve_used_update_types())
        runner=web.AppRunner(app)
        await runner.setup()
        site=web.TCPSite(runner,host='0.0.0.0',port=webhook_port)
        try:
            await site.start()
            print(f'Webhook server listening on 0.0.0.0:{webhook_port}; URL: {webhook_url}')
            await asyncio.Event().wait()
        finally:
            await runner.cleanup()
            await bot.session.close()
    else:
        print('Bot started in polling mode. Set WEBHOOK_HOST to enable webhook mode.')
        try:
            await dp.start_polling(bot)
        finally:
            await bot.session.close()

if __name__=='__main__': asyncio.run(main())
