# -*- coding: utf-8 -*-
"""
هندلر تبلیغ کانال (کمپین ممبرگیری)
=======================================
مراحل:
1) کاربر روی دکمه‌ی «تبلیغ کانال من» میزنه (متن دکمه از پنل قابل تغییره)
2) آیدی/لینک کانالش رو میفرسته
3) ربات چک میکنه که خودش (ربات) توی اون کانال ادمینه یا نه
   (لازمه تا بشه عضویت بقیه رو تایید کرد)
4) کاربر تعداد ممبر (کوین) درخواستیش رو وارد میکنه
5) کوین از حسابش کم میشه و کمپین ساخته میشه
6) طبق درخواست: خبر کمپین جدید با دکمه‌ی ورود به کانال، توی کانال لاگ پست میشه

نکته: با دستور مخفی /campaigns هر کاربر میتونه لیست کمپین‌های خودش و
دکمه‌ی توقف/بازگشت کوین رو ببینه؛ عمدا دکمه‌ی جداگانه‌ای براش توی منو
نذاشتیم که شلوغ نشه.
"""

import html

import telebot
from telebot import types

import database as db
import keyboards as kb
import utils


def register(bot: telebot.TeleBot):

    @bot.message_handler(func=lambda m: utils.is_button(m.text, "campaign"))
    def campaign_start(message):
        user_id = message.from_user.id
        utils.set_state(user_id, "awaiting_channel_id")
        bot.send_message(
            message.chat.id, utils.render_text("campaign_ask_channel"), reply_markup=kb.cancel_kb()
        )

    @bot.message_handler(
        func=lambda m: utils.get_state(m.from_user.id)
        and utils.get_state(m.from_user.id)["state"] == "awaiting_channel_id"
    )
    def receive_channel_id(message):
        user_id = message.from_user.id
        channel_id = utils.normalize_channel_id(message.text)

        try:
            chat = bot.get_chat(channel_id)
        except Exception:
            bot.send_message(message.chat.id, utils.render_text("campaign_not_found"))
            return

        try:
            bot_member = bot.get_chat_member(channel_id, bot.get_me().id)
            if bot_member.status not in ("administrator", "creator"):
                bot.send_message(message.chat.id, utils.render_text("campaign_not_admin"))
                return
        except Exception:
            bot.send_message(message.chat.id, utils.render_text("campaign_not_admin"))
            return

        invite_link = chat.invite_link
        if not invite_link:
            try:
                invite_link = bot.export_chat_invite_link(channel_id)
            except Exception:
                invite_link = None

        if not invite_link:
            if channel_id.startswith("@"):
                # کانال عمومیه، حداقل لینک ساده‌ش همیشه کار میکنه
                invite_link = utils.channel_link(channel_id)
            else:
                bot.send_message(
                    message.chat.id,
                    "⚠️ نتونستم لینک دعوت این کانال رو بسازم. مطمئن شو به ربات دسترسی "
                    "«دعوت کاربران با لینک» رو هم توی تنظیمات ادمین کانال داده باشی، "
                    "بعد دوباره امتحان کن.",
                )
                return

        coin_per_join = db.get_int_setting("coin_per_join", 1)
        utils.set_state(
            user_id,
            "awaiting_member_count",
            {
                "channel_id": channel_id,
                "channel_title": chat.title or channel_id,
                "channel_link": invite_link,
            },
        )
        bot.send_message(
            message.chat.id,
            utils.render_text(
                "campaign_ask_count", channel_title=chat.title, coin_per_join=coin_per_join
            ),
            reply_markup=kb.cancel_kb(),
        )

    @bot.message_handler(
        func=lambda m: utils.get_state(m.from_user.id)
        and utils.get_state(m.from_user.id)["state"] == "awaiting_member_count"
    )
    def receive_member_count(message):
        user_id = message.from_user.id
        text = message.text.strip()
        if not text.isdigit() or int(text) <= 0:
            bot.send_message(message.chat.id, "فقط یه عدد بزرگ‌تر از صفر بفرست 🔢")
            return

        member_count = int(text)
        coin_per_join = db.get_int_setting("coin_per_join", 1)
        needed_coins = member_count * coin_per_join

        balance = db.get_coins(user_id)
        if balance < needed_coins:
            bot.send_message(
                message.chat.id,
                utils.render_text(
                    "campaign_insufficient",
                    needed=utils.fmt_num(needed_coins),
                    balance=utils.fmt_num(balance),
                ),
            )
            utils.clear_state(user_id)
            bot.send_message(message.chat.id, "منوی اصلی:", reply_markup=kb.main_menu(user_id))
            return

        utils.update_state_data(user_id, needed_coins=needed_coins, member_count=member_count)
        data = utils.get_state(user_id)["data"]

        text = utils.render_text(
            "campaign_summary",
            channel_title=data["channel_title"],
            member_count=utils.fmt_num(member_count),
            needed_coins=utils.fmt_num(needed_coins),
        )
        utils.set_state(user_id, "confirm_campaign", data)
        bot.send_message(message.chat.id, text, reply_markup=kb.confirm_campaign_kb())

    @bot.callback_query_handler(func=lambda c: c.data in ("campaign_confirm", "campaign_cancel"))
    def confirm_campaign(call):
        user_id = call.from_user.id
        state = utils.get_state(user_id)
        if not state or state["state"] != "confirm_campaign":
            bot.answer_callback_query(call.id, "این درخواست منقضی شده.", show_alert=True)
            return

        if call.data == "campaign_cancel":
            utils.clear_state(user_id)
            bot.answer_callback_query(call.id, "لغو شد.")
            bot.send_message(call.message.chat.id, "منوی اصلی:", reply_markup=kb.main_menu(user_id))
            return

        data = state["data"]
        needed_coins = data["needed_coins"]
        # فوراً پاک میکنیم - وگرنه اگه کاربر خیلی سریع دوبار روی دکمه بزنه
        # (دابل‌کلیک)، ممکنه دو بار کوین کسر بشه و دو تا کمپین ساخته بشه
        utils.clear_state(user_id)

        ok = db.deduct_coins(user_id, needed_coins)
        if not ok:
            bot.answer_callback_query(call.id, "موجودی کافی نیست.", show_alert=True)
            return

        campaign_id = db.create_campaign(
            owner_id=user_id,
            channel_id=data["channel_id"],
            channel_title=data["channel_title"],
            channel_link=data["channel_link"],
            total_coins=needed_coins,
        )

        bot.answer_callback_query(call.id, "✅ کمپین شروع شد!")

        # اول توی کانال لاگ پست میکنیم تا آیدی پیامش رو داشته باشیم، بعد
        # دکمه‌ی «مشاهده سفارش» رو که مستقیم به همون پست وصله میسازیم
        _post_new_campaign_to_log_channel(bot, campaign_id)
        campaign = db.get_campaign(campaign_id)

        success_text = utils.render_text_html(
            "campaign_success",
            channel_title=html.escape(data["channel_title"]),
            member_count=utils.fmt_num(data["member_count"]),
            order_code=f"<code>{campaign['order_code']}</code>",
        )

        view_markup = None
        log_channel_id = db.get_setting("log_channel_id")
        if campaign["log_message_id"] and log_channel_id:
            view_url = utils.build_message_link(log_channel_id, campaign["log_message_id"])
            view_markup = types.InlineKeyboardMarkup()
            view_markup.add(types.InlineKeyboardButton("👁 مشاهده سفارش", url=view_url))

        bot.send_message(call.message.chat.id, success_text, parse_mode="HTML", reply_markup=view_markup)

    # -----------------------------------------------------------------
    # مشاهده کمپین‌های خودم (دستور مخفی، عمدا دکمه‌ی منو نداره)
    # -----------------------------------------------------------------
    _STATUS_FA = {"active": "🟢 فعال", "finished": "✅ تکمیل‌شده", "stopped": "⛔️ متوقف‌شده"}

    @bot.message_handler(commands=["campaigns"])
    def my_campaigns(message):
        user_id = message.from_user.id
        rows = db.list_campaigns_by_owner(user_id)
        if not rows:
            bot.send_message(message.chat.id, "هنوز هیچ کمپینی نساختی.")
            return
        bot.send_message(message.chat.id, f"📋 {len(rows)} کمپین ثبت‌شده داری:")
        for c in rows:
            done = c["total_coins"] - c["remaining"]
            text = (
                f"#{c['id']} — {c['channel_title']}\n"
                f"وضعیت: {_STATUS_FA.get(c['status'], c['status'])}\n"
                f"پیشرفت: {utils.fmt_num(done)} از {utils.fmt_num(c['total_coins'])} عضو"
            )
            markup = None
            if c["status"] == "active":
                markup = types.InlineKeyboardMarkup()
                markup.add(
                    types.InlineKeyboardButton("⛔️ توقف و بازگشت کوین باقی‌مانده", callback_data=f"stopcamp_{c['id']}")
                )
            bot.send_message(message.chat.id, text, reply_markup=markup)

    @bot.callback_query_handler(func=lambda c: c.data.startswith("stopcamp_"))
    def stop_campaign_cb(call):
        user_id = call.from_user.id
        campaign_id = int(call.data.split("_", 1)[1])
        campaign = db.get_campaign(campaign_id)
        if not campaign or campaign["owner_id"] != user_id:
            bot.answer_callback_query(call.id, "این کمپین مال تو نیست.", show_alert=True)
            return
        refund = db.stop_campaign(campaign_id)
        if refund:
            bot.answer_callback_query(call.id, f"متوقف شد. {refund} کوین برگشت داده شد.", show_alert=True)
            update_log_message(bot, campaign_id)
        else:
            bot.answer_callback_query(call.id, "این کمپین قبلا تموم یا متوقف شده بود.", show_alert=True)
        try:
            bot.edit_message_reply_markup(call.message.chat.id, call.message.message_id, reply_markup=None)
        except Exception:
            pass


    # -----------------------------------------------------------------
    # تشخیص خروج/بازگشت اعضا از کانال‌های تبلیغ‌شده
    # اگه عضوی که از یه کمپین کوین گرفته بود کانال رو ترک کنه، ۱ کوین به
    # صاحب کمپین (تبلیغ‌کننده) به‌عنوان جبران برمیگرده. اگه همون آدم دوباره
    # برگرده، همون ۱ کوین دوباره ازش کسر میشه.
    # -----------------------------------------------------------------
    @bot.chat_member_handler()
    def on_member_status_change(update: types.ChatMemberUpdated):
        try:
            user = update.new_chat_member.user
            if user.is_bot:
                return

            old_status = update.old_chat_member.status
            new_status = update.new_chat_member.status
            was_in = old_status in ("member", "administrator", "creator")
            is_in = new_status in ("member", "administrator", "creator")
            if was_in == is_in:
                return  # این تغییر ربطی به جوین/لفت نداره (مثلا ارتقا به ادمین)

            chat = update.chat
            candidates = []
            if getattr(chat, "username", None):
                candidates.append(f"@{chat.username}")
            candidates.append(str(chat.id))

            campaign = db.find_earning_campaign(user.id, candidates)
            if not campaign:
                return
            channel_id = campaign["channel_id"]

            if was_in and not is_in:
                if db.mark_channel_left(user.id, channel_id):
                    db.add_coins(campaign["owner_id"], 1)
                    try:
                        bot.send_message(
                            campaign["owner_id"],
                            f"⚠️ یکی از اعضایی که از کمپین «{campaign['channel_title']}» عضو "
                            "شده بود، کانال رو ترک کرد.\n۱ کوین به‌عنوان جبران به حسابت برگشت.",
                        )
                    except Exception:
                        pass
            elif is_in and not was_in:
                if db.mark_channel_rejoined(user.id, channel_id):
                    db.force_deduct_coins(campaign["owner_id"], 1)
                    try:
                        bot.send_message(
                            campaign["owner_id"],
                            f"✅ همون عضوی که از کمپین «{campaign['channel_title']}» رفته بود، "
                            "دوباره برگشت.\n۱ کوینی که بابت خروجش جبران شده بود، ازت کسر شد.",
                        )
                    except Exception:
                        pass
        except Exception:
            pass


def _log_message_kb(bot, campaign):
    """دکمه‌های زیر پست کانال لاگ - ورود به کانال، تایید عضویت، و ورود به ربات."""
    link = campaign["channel_link"] or utils.channel_link(campaign["channel_id"])
    markup = types.InlineKeyboardMarkup()
    markup.row(
        types.InlineKeyboardButton("📢 عضویت در کانال", url=link),
        types.InlineKeyboardButton("✅️ تایید عضویت", callback_data=f"verify_{campaign['id']}"),
    )
    try:
        bot_username = bot.get_me().username
        markup.row(types.InlineKeyboardButton("🤖 ربات", url=f"https://t.me/{bot_username}"))
    except Exception:
        pass
    return markup


def _build_log_text(campaign):
    done = campaign["total_coins"] - campaign["remaining"]
    title = html.escape(campaign["channel_title"] or campaign["channel_id"])
    return (
        "🆕 یک کانال جدید برای عضویت اضافه شد!\n"
        f"📢 {title}\n"
        f"👥 تعداد: {utils.fmt_num(campaign['total_coins'])}\n"
        f"✅ انجام شده: {utils.fmt_num(done)}\n"
        f"🆔 کد سفارش: <code>{campaign['order_code']}</code>"
    )


def _post_new_campaign_to_log_channel(bot, campaign_id):
    """
    طبق درخواست: با هر کمپین جدید توی کانال لاگ پست میشه، همراه دکمه‌ی
    ورود به کانال، تایید عضویت، و ورود به ربات. آیدی این پیام ذخیره میشه
    تا بعداً با هر جوین جدید ادیت بشه (یا وقتی سفارش تکمیل شد، حذف بشه).
    """
    log_channel = db.get_setting("log_channel_id")
    if not log_channel:
        return
    campaign = db.get_campaign(campaign_id)
    if not campaign:
        return
    text = _build_log_text(campaign)
    markup = _log_message_kb(bot, campaign)
    try:
        sent = bot.send_message(log_channel, text, reply_markup=markup, parse_mode="HTML")
        db.set_campaign_log_message(campaign_id, sent.message_id)
    except Exception:
        pass


def update_log_message(bot, campaign_id):
    """
    وقتی یه نفر جدید از این کمپین کوین میگیره، تعداد «انجام شده» توی پیام
    کانال لاگ رو بالا میبره. اگه سفارش کامل یا متوقف شده باشه، به‌جای
    ادیت، پیام رو کلا از کانال حذف میکنه که شلوغ نمونه.
    """
    log_channel = db.get_setting("log_channel_id")
    if not log_channel:
        return
    campaign = db.get_campaign(campaign_id)
    if not campaign or not campaign["log_message_id"]:
        return

    if campaign["status"] != "active" or campaign["remaining"] <= 0:
        try:
            bot.delete_message(log_channel, campaign["log_message_id"])
        except Exception:
            pass
        return

    try:
        bot.edit_message_text(
            _build_log_text(campaign),
            log_channel,
            campaign["log_message_id"],
            reply_markup=_log_message_kb(bot, campaign),
            parse_mode="HTML",
        )
    except Exception:
        pass
