# -*- coding: utf-8 -*-
"""
جنگ جهانی بله - نسخه تک فایلی
Python 3.9+ | فقط کتابخانه‌های استاندارد پایتون
API: Bale Bot API (long polling)
مالک: 472269472

نکته: توکن داخل فایل اولیه قرار داده شده است. آن را محرمانه نگه دارید.
برای تغییر توکن از پنل مالک، مقدار جدید را وارد کنید؛ برنامه با توکن تازه
در چرخه بعدی polling ادامه می‌دهد.
"""

import json
import os
import random
import sqlite3
import time
import urllib.parse
import urllib.request
import urllib.error
from contextlib import closing

# -------------------- تنظیمات اصلی --------------------
TOKEN = "55734840:SSwO-OX-3uKr3TJ1dWO8R-9mlQphfospf3I"
OWNER_ID = 472269472
DB_FILE = "world_war.db"
API_ROOT = "https://tapi.bale.ai/bot{}/{}"
POLL_TIMEOUT = 25

DEFAULT_TEXTS = {
    "welcome": "🌍 به فرماندهی جنگ جهانی خوش آمدی!\nکشورت را انتخاب کن و امپراتوری خودت را بساز.",
    "main": "🏛️ ستاد فرماندهی\nیکی از بخش‌های زیر را انتخاب کن:",
    "country": "🏳️ کشور شما: {country}\n💰 خزانه: {money:,}\n👥 نیروی انسانی: {population:,}\n🪖 ارتش: {army:,}\n🛡️ قدرت دفاعی: {defense:,}\n🛢️ نفت: {oil:,}",
    "no_country": "هنوز کشوری انتخاب نکرده‌ای. از بخش «انتخاب کشور» شروع کن.",
    "attack": "⚔️ هدف حمله را انتخاب کن. حمله باعث مصرف نیرو و منابع می‌شود.",
    "owner": "👑 پنل فرمانده کل\nمدیریت بازی از این بخش انجام می‌شود.",
    "help": "📘 راهنما\nبا انتخاب کشور بازی را آغاز کن. از مالیات و تولید برای درآمد استفاده کن، ارتش بساز، دفاع را تقویت کن و با کشورها وارد جنگ یا اتحاد شو.",
    "denied": "⛔ این بخش فقط برای مالک ربات است.",
    "done": "✅ عملیات انجام شد.",
    "error": "⚠️ خطایی رخ داد. دوباره تلاش کن."
}

BUTTONS = {
    "choose": "🏳️ انتخاب کشور", "profile": "📊 کشور من",
    "economy": "💰 اقتصاد", "army": "🪖 ارتش",
    "attack": "⚔️ جنگ", "diplomacy": "🤝 دیپلماسی",
    "ranking": "🏆 رتبه‌بندی", "help": "📘 راهنما",
    "back": "🔙 بازگشت", "owner": "👑 پنل مالک",
    "tax": "📈 دریافت مالیات", "produce": "🏭 تولید منابع",
    "recruit": "➕ سربازگیری", "defense": "🛡️ تقویت دفاع",
    "air": "✈️ نیروی هوایی", "navy": "🚢 نیروی دریایی",
    "missile": "🚀 موشک", "nuke": "☢️ سلاح هسته‌ای",
    "peace": "🕊️ پیشنهاد صلح", "alliance": "🤝 درخواست اتحاد",
    "stats": "📈 آمار کل", "broadcast": "📢 پیام همگانی",
    "edit_text": "✏️ ویرایش متن‌ها", "edit_buttons": "🔘 ویرایش نام دکمه‌ها",
    "set_token": "🔐 تغییر توکن", "add_money": "💵 افزایش خزانه",
    "reset": "♻️ پاک‌سازی بازی"
}

# نام کشورهای مستقل و چند قلمرو برای انتخاب در بازی
COUNTRIES = [
"ایران","افغانستان","پاکستان","هند","چین","ژاپن","کره جنوبی","کره شمالی","روسیه","اوکراین",
"بلاروس","لهستان","آلمان","فرانسه","ایتالیا","اسپانیا","پرتغال","هلند","بلژیک","سوئیس",
"اتریش","سوئد","نروژ","فنلاند","دانمارک","ایسلند","ایرلند","بریتانیا","یونان","ترکیه",
"عراق","سوریه","لبنان","اردن","عربستان","امارات","قطر","بحرین","کویت","عمان","یمن",
"مصر","لیبی","تونس","الجزایر","مراکش","سودان","اتیوپی","اریتره","سومالی","کنیا",
"تانزانیا","اوگاندا","رواندا","بوروندی","نیجریه","غنا","سنگال","مالی","نیجر","چاد",
"کامرون","گابن","کنگو","آنگولا","زامبیا","زیمبابوه","موزامبیک","نامیبیا","بوتسوانا","آفریقای جنوبی",
"آمریکا","کانادا","مکزیک","گواتمالا","کوبا","جامائیکا","هائیتی","جمهوری دومینیکن","کاستاریکا","پاناما",
"کلمبیا","ونزوئلا","اکوادور","پرو","بولیوی","شیلی","آرژانتین","اروگوئه","پاراگوئه","برزیل",
"استرالیا","نیوزیلند","اندونزی","مالزی","سنگاپور","تایلند","ویتنام","کامبوج","لائوس","میانمار",
"بنگلادش","سریلانکا","نپال","بوتان","مالدیو","فیلیپین","مغولستان","قزاقستان","ازبکستان","ترکمنستان",
"قرقیزستان","تاجیکستان","آذربایجان","ارمنستان","گرجستان","قبرس","اسرائیل","فلسطین","آلبانی","صربستان",
"کرواسی","بوسنی و هرزگوین","اسلوونی","مجارستان","رومانی","بلغارستان","مولداوی","چک","اسلواکی","اوکراین",
"استونی","لتونی","لیتوانی","لوکزامبورگ","مالت","موناکو","آندورا","سن مارینو","واتیکان","مقدونیه شمالی",
"مونته‌نگرو","کوزوو","ماداگاسکار","موریس","سیشل","کومور","لسوتو","اسواتینی","جیبوتی","گینه",
"گینه بیسائو","گینه استوایی","سیرالئون","لیبریا","بورکینافاسو","بنین","توگو","ساحل عاج","موریتانی","گامبیا",
"آفریقای مرکزی","سائوتومه و پرنسیپ","کیپ ورد","مالاوی","قبرس شمالی","پاپوآ گینه نو","فیجی","ساموآ","تونگا","وانواتو",
"جزایر سلیمان","کیریباتی","تووالو","نائورو","پالائو","جزایر مارشال","میکرونزی","برونئی","تیمور شرقی","بحرین",
"گرنادا","باربادوس","باهاما","بلیز","سنت لوسیا","دومینیکا","آنتیگوا و باربودا","سنت کیتس و نویس","سنت وینسنت","سورینام",
"گویان","ترینیداد و توباگو","السالوادور","هندوراس","نیکاراگوئه"
]

# -------------------- پایگاه داده --------------------
db = sqlite3.connect(DB_FILE, check_same_thread=False)
db.row_factory = sqlite3.Row
lock = __import__("threading").RLock()

def init_db():
    with lock:
        db.executescript("""
        CREATE TABLE IF NOT EXISTS users(
            uid INTEGER PRIMARY KEY, chat_id TEXT, country TEXT UNIQUE,
            money INTEGER DEFAULT 120000, population INTEGER DEFAULT 500000,
            army INTEGER DEFAULT 10000, defense INTEGER DEFAULT 1000,
            air INTEGER DEFAULT 0, navy INTEGER DEFAULT 0, missiles INTEGER DEFAULT 0,
            nukes INTEGER DEFAULT 0, oil INTEGER DEFAULT 5000, food INTEGER DEFAULT 5000,
            score INTEGER DEFAULT 0, last_action INTEGER DEFAULT 0
        );
        CREATE TABLE IF NOT EXISTS wars(
            id INTEGER PRIMARY KEY AUTOINCREMENT, attacker INTEGER, defender INTEGER,
            status TEXT DEFAULT 'active', started INTEGER
        );
        CREATE TABLE IF NOT EXISTS alliances(
            id INTEGER PRIMARY KEY AUTOINCREMENT, a INTEGER, b INTEGER, status TEXT DEFAULT 'pending'
        );
        CREATE TABLE IF NOT EXISTS settings(key TEXT PRIMARY KEY, value TEXT);
        CREATE TABLE IF NOT EXISTS pending(uid INTEGER PRIMARY KEY, action TEXT, payload TEXT);
        """)
        for k,v in DEFAULT_TEXTS.items():
            db.execute("INSERT OR IGNORE INTO settings(key,value) VALUES(?,?)",( "text_"+k, v))
        for k,v in BUTTONS.items():
            db.execute("INSERT OR IGNORE INTO settings(key,value) VALUES(?,?)",( "button_"+k, v))
        db.commit()

def setting(key, default=""):
    row = db.execute("SELECT value FROM settings WHERE key=?", (key,)).fetchone()
    return row["value"] if row else default

def set_setting(key, value):
    with lock:
        db.execute("INSERT INTO settings(key,value) VALUES(?,?) ON CONFLICT(key) DO UPDATE SET value=excluded.value",(key,str(value)))
        db.commit()

def user(uid):
    return db.execute("SELECT * FROM users WHERE uid=?", (uid,)).fetchone()

def ensure_user(uid, chat_id):
    with lock:
        db.execute("INSERT OR IGNORE INTO users(uid,chat_id) VALUES(?,?)",(uid,str(chat_id)))
        db.execute("UPDATE users SET chat_id=? WHERE uid=?",(str(chat_id),uid))
        db.commit()

def set_pending(uid, action, payload=""):
    db.execute("INSERT INTO pending(uid,action,payload) VALUES(?,?,?) ON CONFLICT(uid) DO UPDATE SET action=excluded.action,payload=excluded.payload",(uid,action,payload))
    db.commit()

def get_pending(uid):
    return db.execute("SELECT * FROM pending WHERE uid=?", (uid,)).fetchone()

def clear_pending(uid):
    db.execute("DELETE FROM pending WHERE uid=?", (uid,))
    db.commit()

# -------------------- ارتباط با API بله --------------------
def api(method, data=None, token=None):
    token = token or TOKEN
    url = API_ROOT.format(token, method)
    payload = urllib.parse.urlencode(data or {}).encode("utf-8")
    req = urllib.request.Request(url, data=payload, headers={"Content-Type":"application/x-www-form-urlencoded"})
    try:
        with urllib.request.urlopen(req, timeout=40) as res:
            raw = res.read().decode("utf-8", "replace")
            obj = json.loads(raw)
            if isinstance(obj, dict) and obj.get("ok") is False:
                raise RuntimeError(obj.get("description","Bale API error"))
            return obj
    except urllib.error.HTTPError as e:
        detail = e.read().decode("utf-8","replace")[:300]
        raise RuntimeError("HTTP {}: {}".format(e.code,detail))
    except Exception as e:
        raise RuntimeError(str(e))

def send(chat_id, text, keyboard=None):
    data = {"chat_id": str(chat_id), "text": str(text)}
    if keyboard:
        data["reply_markup"] = json.dumps({"inline_keyboard":keyboard}, ensure_ascii=False)
    return api("sendMessage", data)

def answer_callback(callback_id, text=""):
    try:
        api("answerCallbackQuery", {"callback_query_id":callback_id,"text":text})
    except Exception:
        pass

def inline(rows):
    out=[]
    for row in rows:
        out.append([{"text":setting("button_"+key, BUTTONS.get(key,key)), "callback_data":key} for key in row])
    return out

def main_menu(uid):
    rows=[["choose","profile"],["economy","army"],["attack","diplomacy"],["ranking","help"]]
    if uid == OWNER_ID:
        rows.append(["owner"])
    return inline(rows)

def owner_menu():
    return inline([["stats","broadcast"],["edit_text","edit_buttons"],["set_token","add_money"],["reset","back"]])

def country_menu():
    return inline([["tax","produce"],["recruit","defense"],["air","navy"],["missile","nuke"],["back"]])

def get_text(key, **kwargs):
    raw=setting("text_"+key, DEFAULT_TEXTS.get(key,""))
    try: return raw.format(**kwargs)
    except Exception: return raw

def country_select_keyboard(page=0):
    size=24
    start=page*size
    chunk=COUNTRIES[start:start+size]
    rows=[]
    for i in range(0,len(chunk),2):
        row=[]
        for name in chunk[i:i+2]:
            row.append({"text":name,"callback_data":"c:"+str(COUNTRIES.index(name))})
        rows.append(row)
    nav=[]
    if page>0: nav.append({"text":"⬅️ قبلی","callback_data":"cp:"+str(page-1)})
    if start+size<len(COUNTRIES): nav.append({"text":"بعدی ➡️","callback_data":"cp:"+str(page+1)})
    if nav: rows.append(nav)
    rows.append([{"text":setting("button_back",BUTTONS["back"]),"callback_data":"back"}])
    return rows

def send_home(chat_id, uid, text=None):
    send(chat_id, text or get_text("main"), main_menu(uid))

def choose_country(chat_id, uid, index):
    if not 0 <= index < len(COUNTRIES): return
    name=COUNTRIES[index]
    current=user(uid)
    if current and current["country"]:
        send(chat_id,"شما قبلاً کشور «{}» را انتخاب کرده‌اید. تغییر کشور فقط با تأیید مالک ممکن است.".format(current["country"]),main_menu(uid))
        return
    taken=db.execute("SELECT uid FROM users WHERE country=?",(name,)).fetchone()
    if taken:
        send(chat_id,"این کشور قبلاً انتخاب شده است. کشور دیگری انتخاب کن.",country_select_keyboard(0)); return
    db.execute("UPDATE users SET country=? WHERE uid=?",(name,uid)); db.commit()
    send(chat_id,"🎉 کشور «{}» به شما واگذار شد!\nاکنون فرماندهی را آغاز کن.".format(name),country_menu())

def profile_text(u):
    return get_text("country",country=u["country"] or "انتخاب نشده",money=u["money"],population=u["population"],army=u["army"],defense=u["defense"],oil=u["oil"])

def require_country(chat_id, uid):
    u=user(uid)
    if not u or not u["country"]:
        send(chat_id,get_text("no_country"),main_menu(uid)); return None
    return u

def economy(chat_id, uid):
    u=require_country(chat_id,uid)
    if not u:return
    send(chat_id,"💰 اقتصاد کشور {}\nخزانه: {:,}\nنفت: {:,}\nغذا: {:,}\n\nمالیات برای دریافت درآمد و تولید برای افزایش ذخایر است.".format(u["country"],u["money"],u["oil"],u["food"]),inline([["tax","produce"],["back"]]))

def army_page(chat_id,uid):
    u=require_country(chat_id,uid)
    if not u:return
    send(chat_id,"🪖 نیروهای مسلح {}\nسرباز: {:,}\nدفاع: {:,}\nهواپیما: {:,}\nناو: {:,}\nموشک: {:,}\nکلاهک هسته‌ای: {:,}".format(u["country"],u["army"],u["defense"],u["air"],u["navy"],u["missiles"],u["nukes"]),country_menu())

def tax(uid,chat_id):
    u=require_country(chat_id,uid)
    if not u:return
    income=max(1000,int(u["population"]*0.08))
    db.execute("UPDATE users SET money=money+?,score=score+? WHERE uid=?",(income,income//100,uid));db.commit()
    send(chat_id,"📈 مالیات دریافت شد: {:,} سکه".format(income),country_menu())

def produce(uid,chat_id):
    u=require_country(chat_id,uid)
    if not u:return
    oil=random.randint(150,500); food=random.randint(300,800)
    db.execute("UPDATE users SET oil=oil+?,food=food+? WHERE uid=?",(oil,food,uid));db.commit()
    send(chat_id,"🏭 تولید انجام شد:\n🛢️ +{} نفت\n🌾 +{} غذا".format(oil,food),country_menu())

def recruit(uid,chat_id):
    u=require_country(chat_id,uid)
    if not u:return
    cost=5000; count=1000
    if u["money"]<cost or u["food"]<500:
        send(chat_id,"منابع کافی نیست. به ۵۰۰۰ سکه و ۵۰۰ غذا نیاز داری.",country_menu());return
    db.execute("UPDATE users SET money=money-?,food=food-500,army=army+?,score=score+50 WHERE uid=?",(cost,count,uid));db.commit()
    send(chat_id,"🪖 ۱۰۰۰ سرباز جدید به ارتش پیوستند.",country_menu())

def upgrade(uid,chat_id,kind):
    u=require_country(chat_id,uid)
    if not u:return
    costs={"defense":(7000, "defense",500),"air":(15000,"air",10),"navy":(18000,"navy",5),"missile":(25000,"missiles",2),"nuke":(100000,"nukes",1)}
    cost,col,amount=costs[kind]
    if u["money"]<cost:
        send(chat_id,"💸 خزانه کافی نیست. هزینه: {:,}".format(cost),country_menu());return
    db.execute("UPDATE users SET money=money-?,{}={}+?,score=score+100 WHERE uid=?".format(col,col),(cost,amount,uid));db.commit()
    send(chat_id,"✅ ارتقا انجام شد: {} واحد به {}".format(amount,col),country_menu())

def attack_page(chat_id,uid,page=0):
    u=require_country(chat_id,uid)
    if not u:return
    others=db.execute("SELECT uid,country,army,defense FROM users WHERE country IS NOT NULL AND uid<>? ORDER BY country",(uid,)).fetchall()
    if not others:
        send(chat_id,"هنوز کشور دیگری وارد بازی نشده است.",inline([["back"]]));return
    rows=[]
    for x in others[page*20:(page+1)*20]:
        rows.append([{"text":"⚔️ "+x["country"],"callback_data":"atk:"+str(x["uid"])}])
    nav=[]
    if page>0:nav.append({"text":"⬅️","callback_data":"ap:"+str(page-1)})
    if (page+1)*20<len(others):nav.append({"text":"➡️","callback_data":"ap:"+str(page+1)})
    if nav:rows.append(nav)
    rows.append([{"text":setting("button_back",BUTTONS["back"]),"callback_data":"back"}])
    send(chat_id,get_text("attack"),rows)

def do_attack(chat_id,uid,target):
    a=require_country(chat_id,uid)
    d=user(target)
    if not a or not d or not d["country"]:
        send(chat_id,"هدف معتبر نیست.",main_menu(uid));return
    if a["army"]<1000:
        send(chat_id,"برای حمله حداقل ۱۰۰۰ سرباز لازم داری.",country_menu());return
    if db.execute("SELECT id FROM wars WHERE attacker=? AND defender=? AND status='active'",(uid,target)).fetchone():
        send(chat_id,"با این کشور در حال جنگ هستی.",main_menu(uid));return
    power=a["army"]+a["air"]*500+a["navy"]*300
    defense=d["army"]//2+d["defense"]+d["air"]*250
    win=power*random.uniform(.75,1.25)>defense*random.uniform(.75,1.25)
    loss=min(a["army"],random.randint(500,1500))
    db.execute("UPDATE users SET army=army-? WHERE uid=?",(loss,uid))
    if win:
        loot=min(d["money"],random.randint(1000,10000))
        db.execute("UPDATE users SET money=money+?,score=score+500 WHERE uid=?",(loot,uid))
        db.execute("UPDATE users SET money=money-?,defense=MAX(0,defense-100) WHERE uid=?",(loot,target))
        result="🏆 پیروزی! غنیمت: {:,} سکه".format(loot)
    else:
        result="🛑 حمله ناموفق بود؛ ارتش خسارت دید."
    db.execute("INSERT INTO wars(attacker,defender,status,started) VALUES(?,?,?,?)",(uid,target,"won" if win else "repelled",int(time.time())))
    db.commit()
    send(chat_id,result+"\nتلفات نیروهای شما: {:,}".format(loss),main_menu(uid))
    try: send(d["chat_id"],"⚔️ کشور شما از سوی «{}» مورد حمله قرار گرفت.\n{}".format(a["country"],"دفاع موفق بود." if not win else "بخشی از خزانه از دست رفت."))
    except Exception: pass

def diplomacy(chat_id,uid):
    u=require_country(chat_id,uid)
    if not u:return
    others=db.execute("SELECT uid,country FROM users WHERE country IS NOT NULL AND uid<>? ORDER BY country",(uid,)).fetchall()
    rows=[]
    for x in others[:30]:
        rows.append([{"text":"🤝 "+x["country"],"callback_data":"ally:"+str(x["uid"])}])
    rows.append([{"text":setting("button_back",BUTTONS["back"]),"callback_data":"back"}])
    send(chat_id,"🤝 کشور موردنظر برای درخواست اتحاد را انتخاب کن:",rows)

def alliance_request(chat_id,uid,target):
    if not require_country(chat_id,uid):return
    d=user(target)
    if not d or not d["country"]:return
    db.execute("INSERT INTO alliances(a,b,status) VALUES(?,?,?)",(uid,target,"pending"));db.commit()
    send(chat_id,"درخواست اتحاد برای {} ارسال شد.".format(d["country"]),main_menu(uid))
    try:send(d["chat_id"],"🤝 کشور {} درخواست اتحاد فرستاده است.".format(user(uid)["country"]),[[{"text":"✅ پذیرش اتحاد","callback_data":"accept:"+str(uid)}],[{"text":"❌ رد","callback_data":"reject:"+str(uid)}]])
    except Exception:pass

def ranking(chat_id):
    rows=db.execute("SELECT country,score,money,army FROM users WHERE country IS NOT NULL ORDER BY score DESC LIMIT 15").fetchall()
    if not rows:
        send(chat_id,"هنوز رتبه‌بندی ثبت نشده است.",None);return
    lines=["🏆 رتبه‌بندی قدرت کشورها"]
    for i,r in enumerate(rows,1):
        lines.append("{}. {} | امتیاز: {:,} | ارتش: {:,}".format(i,r["country"],r["score"],r["army"]))
    send(chat_id,"\n".join(lines),None)

# -------------------- پنل مالک --------------------
def owner_stats(chat_id):
    users=db.execute("SELECT COUNT(*) n,COUNT(country) c,COALESCE(SUM(money),0) m,COALESCE(SUM(army),0) a FROM users").fetchone()
    wars=db.execute("SELECT COUNT(*) n FROM wars").fetchone()["n"]
    send(chat_id,"📊 آمار کل بازی\n👤 کاربران: {}\n🏳️ کشورهای انتخاب‌شده: {}\n💰 مجموع خزانه: {:,}\n🪖 مجموع ارتش: {:,}\n⚔️ نبردهای ثبت‌شده: {}".format(users["n"],users["c"],users["m"],users["a"],wars),owner_menu())

def ask_broadcast(chat_id,uid):
    set_pending(uid,"broadcast")
    send(chat_id,"متن پیام همگانی را ارسال کن. برای لغو «لغو» را بفرست.")

def ask_edit(chat_id,uid,kind):
    options=DEFAULT_TEXTS if kind=="text" else BUTTONS
    keys=list(options.keys())
    rows=[]
    for k in keys:
        rows.append([{"text":k+" : "+setting(("text_" if kind=="text" else "button_")+k,options[k])[:35],"callback_data":"ed:"+kind+":"+k}])
    rows.append([{"text":"🔙 بازگشت","callback_data":"owner"}])
    send(chat_id,"موردی را برای ویرایش انتخاب کن:",rows)

def owner_action(chat_id,uid,action):
    if uid!=OWNER_ID:
        send(chat_id,get_text("denied"));return
    if action=="stats":owner_stats(chat_id)
    elif action=="broadcast":ask_broadcast(chat_id,uid)
    elif action=="edit_text":ask_edit(chat_id,uid,"text")
    elif action=="edit_buttons":ask_edit(chat_id,uid,"button")
    elif action=="set_token":
        set_pending(uid,"set_token")
        send(chat_id,"🔐 توکن جدید را ارسال کن. توکن ذخیره می‌شود و در چرخه بعدی فعال خواهد شد.")
    elif action=="add_money":
        set_pending(uid,"add_money")
        send(chat_id,"شناسه عددی کاربر و مبلغ را با فاصله بفرست. نمونه: 123456 50000")
    elif action=="reset":
        send(chat_id,"برای تأیید پاک‌سازی کامل اطلاعات بازی، دکمه زیر را بزن.",[[{"text":"تأیید پاک‌سازی","callback_data":"reset_yes"}],[{"text":"انصراف","callback_data":"owner"}]])
    else:send(chat_id,get_text("owner"),owner_menu())

def handle_pending(chat_id,uid,text):
    p=get_pending(uid)
    if not p:return False
    action=p["action"]
    if text.strip()=="لغو":
        clear_pending(uid);send(chat_id,"عملیات لغو شد.",owner_menu() if uid==OWNER_ID else main_menu(uid));return True
    if uid!=OWNER_ID:
        clear_pending(uid);return False
    if action=="broadcast":
        clear_pending(uid)
        rows=db.execute("SELECT chat_id FROM users").fetchall()
        ok=0
        for r in rows:
            try:send(r["chat_id"],text);ok+=1;time.sleep(.04)
            except Exception:pass
        send(chat_id,"📢 پیام برای {} کاربر ارسال شد.".format(ok),owner_menu())
    elif action.startswith("edit:"):
        _,kind,key=action.split(":",2)
        set_setting(("text_" if kind=="text" else "button_")+key,text)
        clear_pending(uid);send(chat_id,"✅ تنظیم ذخیره شد.",owner_menu())
    elif action=="set_token":
        if len(text.strip())<15:
            send(chat_id,"توکن کوتاه است؛ دوباره ارسال کن یا «لغو».");return True
        global TOKEN
        TOKEN=text.strip()
        set_setting("runtime_token",TOKEN)
        clear_pending(uid)
        send(chat_id,"✅ توکن جدید در حافظه فعال شد. برای ماندگاری پس از راه‌اندازی مجدد، توکن در فایل تنظیمات ذخیره نمی‌شود؛ آن را در محیط امن میزبان تنظیم کن.",owner_menu())
    elif action=="add_money":
        try:
            parts=text.split()
            target=int(parts[0]);amount=int(parts[1])
            if amount<=0:raise ValueError()
            db.execute("UPDATE users SET money=money+? WHERE uid=?",(amount,target));db.commit()
            clear_pending(uid);send(chat_id,"✅ مبلغ {:,} به خزانه کاربر افزوده شد.".format(amount),owner_menu())
        except Exception:send(chat_id,"قالب درست: شناسه مبلغ — نمونه: 123456 50000")
    return True

def process_message(msg):
    chat=msg.get("chat",{}); sender=msg.get("from",{})
    chat_id=chat.get("id"); uid=sender.get("id")
    if chat_id is None or uid is None:return
    uid=int(uid);ensure_user(uid,chat_id)
    txt=msg.get("text","")
    if txt and get_pending(uid):
        if handle_pending(chat_id,uid,txt):return
    if txt in ("/start","/start@"+str(sender.get("username",""))):
        send(chat_id,get_text("welcome"),main_menu(uid));return
    # همه امکانات بازی از دکمه انجام می‌شود؛ متن آزاد فقط راهنماست.
    send(chat_id,"برای انجام عملیات از دکمه‌های منو استفاده کن.",main_menu(uid))

def process_callback(cb):
    data=cb.get("data",""); msg=cb.get("message",{})
    chat_id=msg.get("chat",{}).get("id")
    sender=cb.get("from",{});uid=sender.get("id")
    if chat_id is None or uid is None:return
    uid=int(uid);ensure_user(uid,chat_id)
    answer_callback(cb.get("id",""))
    if data.startswith("cp:"):
        send(chat_id,"🏳️ انتخاب کشور",country_select_keyboard(int(data.split(":")[1])));return
    if data.startswith("c:"):
        choose_country(chat_id,uid,int(data.split(":")[1]));return
    if data.startswith("ap:"):
        attack_page(chat_id,uid,int(data.split(":")[1]));return
    if data.startswith("atk:"):
        do_attack(chat_id,uid,int(data.split(":")[1]));return
    if data.startswith("ally:"):
        alliance_request(chat_id,uid,int(data.split(":")[1]));return
    if data.startswith("accept:") or data.startswith("reject:"):
        other=int(data.split(":")[1]); status="accepted" if data.startswith("accept:") else "rejected"
        db.execute("UPDATE alliances SET status=? WHERE a=? AND b=? AND status='pending'",(status,other,uid));db.commit()
        send(chat_id,"🤝 وضعیت درخواست: "+("اتحاد برقرار شد." if status=="accepted" else "درخواست رد شد."),main_menu(uid));return
    if data.startswith("ed:"):
        if uid!=OWNER_ID:send(chat_id,get_text("denied"));return
        _,kind,key=data.split(":",2)
        set_pending(uid,"edit:"+kind+":"+key)
        send(chat_id,"مقدار جدید را ارسال کن. برای لغو «لغو» را بفرست.")
        return
    if data=="reset_yes" and uid==OWNER_ID:
        db.execute("DELETE FROM users");db.execute("DELETE FROM wars");db.execute("DELETE FROM alliances");db.execute("DELETE FROM pending");db.commit()
        send(chat_id,"♻️ اطلاعات بازی پاک شد. تنظیمات پنل حفظ شدند.",owner_menu());return
    if data=="owner":
        if uid==OWNER_ID:send(chat_id,get_text("owner"),owner_menu())
        else:send(chat_id,get_text("denied"))
    elif data=="back":send_home(chat_id,uid)
    elif data=="choose":send(chat_id,"🏳️ کشور خود را انتخاب کن:",country_select_keyboard(0))
    elif data=="profile":
        u=require_country(chat_id,uid)
        if u:send(chat_id,profile_text(u),country_menu())
    elif data=="economy":economy(chat_id,uid)
    elif data=="army":army_page(chat_id,uid)
    elif data=="attack":attack_page(chat_id,uid)
    elif data=="diplomacy":diplomacy(chat_id,uid)
    elif data=="ranking":ranking(chat_id)
    elif data=="help":send(chat_id,get_text("help"),main_menu(uid))
    elif data=="tax":tax(uid,chat_id)
    elif data=="produce":produce(uid,chat_id)
    elif data=="recruit":recruit(uid,chat_id)
    elif data in ("defense","air","navy","missile","nuke"):upgrade(uid,chat_id,data)
    elif data in ("stats","broadcast","edit_text","edit_buttons","set_token","add_money","reset"):
        owner_action(chat_id,uid,data)
    else:send(chat_id,"این گزینه شناخته نشد.",main_menu(uid))

def extract_updates(obj):
    if isinstance(obj,dict):
        return obj.get("result",[]) or obj.get("updates",[])
    return []

def main():
    global TOKEN
    init_db()
    # آخرین توکنی که مالک از پنل تنظیم کرده، پس از راه‌اندازی مجدد هم بازیابی می‌شود.
    TOKEN = setting("runtime_token", TOKEN)
    print("World War Bale bot starting. Owner:",OWNER_ID)
    offset=None
    while True:
        try:
            params={"timeout":POLL_TIMEOUT}
            if offset is not None:params["offset"]=offset
            result=api("getUpdates",params)
            for upd in extract_updates(result):
                try:
                    uid=upd.get("update_id")
                    if uid is not None:offset=int(uid)+1
                    if upd.get("message"):process_message(upd["message"])
                    elif upd.get("callback_query"):process_callback(upd["callback_query"])
                    elif upd.get("callback"):process_callback(upd["callback"])
                except Exception as e:
                    print("Update error:",repr(e))
        except KeyboardInterrupt:
            print("Stopped.");break
        except Exception as e:
            print("Polling error:",repr(e))
            time.sleep(3)

if __name__=="__main__":
    main()
