"""موتور بازی‌ها: تاس، سنگ‌کاغذقیچی، پنالتی.

جریان هر بازی:
  شروع بازی -> ربات مبلغ ورودی را می‌پرسد -> سازنده مبلغ را می‌نویسد (و سکه‌اش کم می‌شود)
  -> بازیکن دوم با نوشتن کلمه بازی (مثلا «تاس») یا «شرکت» وارد می‌شود و همان مبلغ کم می‌شود
  -> بازی انجام می‌شود -> جایزه = مجموع ورودی‌ها منهای کارمزد، به برنده واریز می‌شود.
اگر بازی لغو یا مساوی شود، سکه‌ها برگردانده می‌شوند.
"""
import random
import time

import config

KINDS = {
    "dice": {"title": "🎲 تاس", "keywords": {"تاس"}},
    "rps": {"title": "✂️ سنگ‌کاغذقیچی", "keywords": {"سنگ کاغذ قیچی", "سکق"}},
    "penalty": {"title": "⚽ پنالتی", "keywords": {"پنالتی"}},
}
START_WORDS = {
    "شروع تاس": "dice",
    "شروع سنگ کاغذ قیچی": "rps",
    "شروع پنالتی": "penalty",
}
RPS = {"سنگ": "🪨", "کاغذ": "📄", "قیچی": "✂️"}
RPS_BEATS = {"سنگ": "قیچی", "کاغذ": "سنگ", "قیچی": "کاغذ"}
DIRS = {"چپ": "⬅️", "وسط": "⬆️", "راست": "➡️"}
FACES = {1: "⚀", 2: "⚁", 3: "⚂", 4: "⚃", 5: "⚄", 6: "⚅"}


class Game:
    def __init__(self, kind, chat, creator):
        self.kind = kind
        self.chat = chat
        self.creator = creator
        self.state = "ask_bet"          # ask_bet -> joining -> playing
        self.bet = 0
        self.capacity = 2
        self.players: list[str] = []
        self.deadline = time.time() + config.BET_ASK_TIMEOUT
        self.picks: dict = {}
        self.round = 0
        self.ties = 0
        self.score: dict[str, int] = {}


class GameManager:
    def __init__(self, db):
        self.db = db
        self.games: dict[str, Game] = {}

    # ------------------------------------------------------------ شروع
    def start(self, chat, uid, kind):
        if chat in self.games:
            return ["⚠️ در این گروه یک بازی فعال وجود دارد. با «لغو» می‌توانید آن را لغو کنید."]
        self.games[chat] = Game(kind, chat, uid)
        return [f"{KINDS[kind]['title']}\n💰 مبلغ ورودی هر بازیکن چند سکه باشه؟\n"
                f"(عدد بین {config.MIN_BET} تا {config.MAX_BET} بفرست — {config.BET_ASK_TIMEOUT} ثانیه وقت داری)"]

    def active(self, chat):
        return self.games.get(chat)

    # ------------------------------------------------------------ لغو
    def cancel(self, chat, uid, is_admin, reason="لغو شد"):
        g = self.games.get(chat)
        if not g:
            return ["بازی فعالی وجود ندارد."]
        if uid != g.creator and not is_admin:
            return ["❌ فقط سازنده بازی یا ادمین می‌تواند بازی را لغو کند."]
        self._refund(g)
        del self.games[chat]
        return [f"❌ بازی {reason}. سکه‌ها به بازیکنان برگردانده شد."]

    def _refund(self, g):
        for p in g.players:
            self.db.add_coins(p, g.bet)

    # ------------------------------------------------------------ پیام متنی
    def on_text(self, chat, uid, text):
        """خروجی: (handled, messages, delete_user_message)"""
        g = self.games.get(chat)
        if not g:
            return False, [], False

        if g.state == "ask_bet":
            if uid != g.creator or not text.isdigit():
                return False, [], False
            bet = int(text)
            if not config.MIN_BET <= bet <= config.MAX_BET:
                return True, [f"مبلغ باید بین {config.MIN_BET} تا {config.MAX_BET} باشد."], False
            if not self.db.add_coins(uid, -bet):
                del self.games[chat]
                return True, [f"❌ موجودی کافی نیست (موجودی: {self.db.coins(uid)})."], False
            g.bet = bet
            g.players = [uid]
            g.state = "joining"
            g.deadline = time.time() + config.JOIN_TIMEOUT
            return True, [self._lobby(g)], False

        if g.state == "joining":
            kw = KINDS[g.kind]["keywords"] | {"شرکت"}
            if text not in kw:
                return False, [], False
            if uid in g.players:
                return True, ["شما قبلا ثبت‌نام کرده‌اید."], False
            if not self.db.add_coins(uid, -g.bet):
                return True, [f"❌ موجودی کافی نیست. ورودی: {g.bet} | موجودی شما: {self.db.coins(uid)}"], False
            g.players.append(uid)
            msgs = [f"✅ {self.db.name(uid)} به بازی پیوست!"]
            if len(g.players) >= g.capacity:
                msgs += self._begin(g)
            else:
                msgs.append(f"📌 {g.capacity - len(g.players)} نفر دیگر نیاز است.")
            return True, msgs, False

        if g.state == "playing":
            return self._on_pick(g, uid, text)
        return False, [], False

    def _lobby(self, g):
        pool = g.bet * g.capacity
        fee = pool * config.FEE_PERCENT // 100
        return (f"{KINDS[g.kind]['title']} — ثبت‌نام شروع شد\n──────────\n"
                f"👥 ظرفیت: {g.capacity} نفر\n💳 ورودی هر نفر: {g.bet} سکه\n"
                f"🏆 جایزه: {pool - fee} سکه\n🧾 کارمزد ({config.FEE_PERCENT}٪): {fee} سکه\n\n"
                f"✅ برای شرکت بنویس «{sorted(KINDS[g.kind]['keywords'])[0]}»\n"
                f"⏱ مهلت: {config.JOIN_TIMEOUT // 60} دقیقه\n❌ لغو: «لغو»")

    # ------------------------------------------------------------ اجرا
    def _begin(self, g):
        g.state = "playing"
        g.deadline = time.time() + config.PICK_TIMEOUT
        if g.kind == "dice":
            return self._play_dice(g)
        if g.kind == "rps":
            return ["✂️ بازی شروع شد! هر دو بازیکن یکی از «سنگ»، «کاغذ» یا «قیچی» را بفرستند.\n"
                    "(پیام انتخاب شما پاک می‌شود تا حریف نبیند)"]
        g.score = {p: 0 for p in g.players}
        return self._penalty_prompt(g)

    # ---------- تاس ----------
    def _play_dice(self, g):
        msgs = ["🎲 بازی تاس شروع شد!"]
        while True:
            rolls = {p: random.randint(1, 6) for p in g.players}
            msgs.append("\n".join(f"{FACES[v]} {self.db.name(p)}: {v}" for p, v in rolls.items()))
            top = max(rolls.values())
            winners = [p for p, v in rolls.items() if v == top]
            if len(winners) == 1:
                break
            msgs.append("🤝 مساوی شد! دوباره تاس می‌اندازیم...")
        return msgs + self._finish(g, winners[0])

    # ---------- انتخاب‌ها (سنگ‌کاغذقیچی / پنالتی) ----------
    def _on_pick(self, g, uid, text):
        if uid not in g.players:
            return False, [], False
        if g.kind == "rps":
            if text not in RPS or uid in g.picks:
                return False, [], False
            g.picks[uid] = text
            if len(g.picks) < 2:
                return True, [f"✅ انتخاب {self.db.name(uid)} ثبت شد."], True
            return True, self._resolve_rps(g), True
        if g.kind == "penalty":
            shooter, keeper = self._roles(g)
            if text not in DIRS:
                return False, [], False
            if uid == shooter and "shoot" not in g.picks:
                g.picks["shoot"] = text
            elif uid == keeper and "keep" not in g.picks:
                g.picks["keep"] = text
            else:
                return False, [], False
            if len(g.picks) < 2:
                return True, ["✅ انتخاب ثبت شد."], True
            return True, self._resolve_penalty(g), True
        return False, [], False

    def _resolve_rps(self, g):
        a, b = g.players
        pa, pb = g.picks[a], g.picks[b]
        line = f"{RPS[pa]} {self.db.name(a)}  ⚔️  {self.db.name(b)} {RPS[pb]}"
        g.picks = {}
        if pa == pb:
            g.ties += 1
            if g.ties >= 3:
                self._refund(g)
                self.games.pop(g.chat, None)
                return [line, "🤝 سه بار مساوی شد؛ بازی بدون برنده تمام شد و سکه‌ها برگشت."]
            g.deadline = time.time() + config.PICK_TIMEOUT
            return [line, "🤝 مساوی! دوباره انتخاب کنید."]
        winner = a if RPS_BEATS[pa] == pb else b
        return [line] + self._finish(g, winner)

    def _roles(self, g):
        a, b = g.players
        return (a, b) if g.round % 2 == 0 else (b, a)

    def _penalty_prompt(self, g):
        shooter, keeper = self._roles(g)
        return [f"⚽ شوت {g.round + 1}\n🥅 شوت‌زن: {self.db.name(shooter)}\n🧤 دروازه‌بان: {self.db.name(keeper)}\n"
                f"هر دو یکی از «چپ»، «وسط» یا «راست» را بفرستند."]

    def _resolve_penalty(self, g):
        shooter, keeper = self._roles(g)
        s, k = g.picks["shoot"], g.picks["keep"]
        goal = s != k
        if goal:
            g.score[shooter] += 1
        a, b = g.players
        msgs = [f"{DIRS[s]} شوت  |  {DIRS[k]} دروازه‌بان\n" + ("⚽ گل!" if goal else "🧤 مهار شد!") +
                f"\n📊 {self.db.name(a)} {g.score[a]} - {g.score[b]} {self.db.name(b)}"]
        g.picks = {}
        g.round += 1
        done_regular = g.round >= config.PENALTY_ROUNDS and g.round % 2 == 0
        if done_regular and g.score[a] != g.score[b]:
            return msgs + self._finish(g, a if g.score[a] > g.score[b] else b)
        if g.round >= 20:
            self._refund(g)
            self.games.pop(g.chat, None)
            return msgs + ["🤝 بازی مساوی ماند؛ سکه‌ها برگشت."]
        g.deadline = time.time() + config.PICK_TIMEOUT
        return msgs + self._penalty_prompt(g)

    # ---------- پایان ----------
    def _finish(self, g, winner):
        pool = g.bet * len(g.players)
        fee = pool * config.FEE_PERCENT // 100
        prize = pool - fee
        self.db.add_coins(winner, prize)
        self.db.add_result(winner, [p for p in g.players if p != winner])
        self.db.add_history(g.chat, g.kind, g.players, g.bet, winner, prize, fee)
        self.games.pop(g.chat, None)
        return [f"🏆 برنده: {self.db.name(winner)}\n💰 جایزه: {prize} سکه\n"
                f"🧾 کارمزد ({config.FEE_PERCENT}٪): {fee} سکه\n"
                f"💳 موجودی جدید: {self.db.coins(winner)}"]

    # ------------------------------------------------------------ زمان‌سنج
    def tick(self):
        """هر چند ثانیه صدا زده می‌شود؛ لیست (chat, پیام) برمی‌گرداند."""
        out, now = [], time.time()
        for chat, g in list(self.games.items()):
            if now < g.deadline:
                continue
            if g.state == "ask_bet":
                del self.games[chat]
                out.append((chat, "⏱ مهلت وارد کردن مبلغ تمام شد؛ بازی لغو شد."))
            elif g.state == "joining":
                self._refund(g)
                del self.games[chat]
                out.append((chat, "⏱ مهلت ثبت‌نام تمام شد؛ بازی لغو و سکه‌ها برگردانده شد."))
            elif g.state == "playing":
                missing = self._missing(g)
                if len(missing) == 2 or not missing:
                    self._refund(g)
                    del self.games[chat]
                    out.append((chat, "⏱ هیچ‌کس پاسخ نداد؛ بازی لغو و سکه‌ها برگشت."))
                else:
                    loser = missing[0]
                    winner = next(p for p in g.players if p != loser)
                    out.append((chat, f"⏱ {self.db.name(loser)} به‌موقع پاسخ نداد و بازی را باخت."))
                    for m in self._finish(g, winner):
                        out.append((chat, m))
        return out

    def _missing(self, g):
        if g.kind == "rps":
            return [p for p in g.players if p not in g.picks]
        shooter, keeper = self._roles(g)
        m = []
        if "shoot" not in g.picks:
            m.append(shooter)
        if "keep" not in g.picks:
            m.append(keeper)
        return m
