from __future__ import annotations

import html
import logging
from datetime import datetime
from zoneinfo import ZoneInfo

from telebot.apihelper import ApiTelegramException

from src import keyboards
from src.config import settings
from src.repositories import repo
from src.services import log_service
from src.services.scheduler import schedule_delete
from src.telegram_text import html_to_plain_text

log = logging.getLogger(__name__)



def joined(bot, user_id: int) -> tuple[bool, list]:
    if user_id in settings.admin_ids:
        return True, []
    missing = []
    for channel in repo.fsubs():
        try:
            status = bot.get_chat_member(channel["chat_id"], user_id).status
            if status not in ("member", "administrator", "creator"):
                missing.append(channel)
        except Exception:
            log.warning("Gagal memeriksa membership channel %s", channel["chat_id"], exc_info=True)
            missing.append(channel)
    return not missing, missing


def _safe_send_media(bot, chat_id: int, media, fmt_vars: dict | None = None):
    # Caption kosong berarti media mengikuti caption default terbaru.
    raw_caption = media["user_caption"] or repo.setting("default_video_caption")
    if fmt_vars:
        if "{total_views}" in raw_caption:
            try:
                caption = raw_caption.format(**fmt_vars)
            except (KeyError, ValueError):
                caption = raw_caption
        else:
            # Caption kustom tanpa placeholder → format apa yang ada, lalu sisipkan stats
            try:
                caption = raw_caption.format(**fmt_vars)
            except (KeyError, ValueError):
                caption = raw_caption
            caption += (
                f"\n\n👁 Ditonton: <b>{fmt_vars.get('total_views', 0)}</b> kali\n"
                f"👥 Penonton: <b>{fmt_vars.get('total_viewers', 0)}</b> orang"
            )
    else:
        caption = raw_caption

    kwargs = dict(
        caption=caption,
        parse_mode="HTML",
        protect_content=settings.protect_content,
    )
    try:
        return bot.send_video(chat_id, media["telegram_file_id"], **kwargs)
    except ApiTelegramException as video_error:
        log.warning("send_video gagal, mencoba document: %s", video_error)
        try:
            return bot.send_document(chat_id, media["telegram_file_id"], **kwargs)
        except ApiTelegramException as document_error:
            # Caption HTML invalid tidak boleh menggagalkan pengiriman file.
            if "parse entities" in str(document_error).lower() or "can't parse" in str(document_error).lower():
                plain = html_to_plain_text(caption)
                return bot.send_document(
                    chat_id,
                    media["telegram_file_id"],
                    caption=plain,
                    protect_content=settings.protect_content,
                )
            raise



def _maintenance_active(user_id: int) -> bool:
    return user_id not in settings.admin_ids and repo.setting("maintenance_mode", "0") == "1"


def _maintenance_message(bot, chat_id: int):
    text = repo.setting(
        "maintenance_text",
        "🔧 Bot sedang dalam pemeliharaan. Silakan coba kembali beberapa saat lagi.",
    )
    return bot.send_message(chat_id, text)

def send_media(bot, chat_id: int, user_id: int, code: str):
    if _maintenance_active(user_id):
        return _maintenance_message(bot, chat_id)

    media = repo.media_by_code(code)
    if not media:
        return bot.send_message(chat_id, "❌ Media tidak ditemukan atau telah dihapus.")

    user = repo.user(user_id)
    if user and user["is_banned"]:
        return bot.send_message(chat_id, "⛔ Akses Anda diblokir admin.")

    is_joined, _missing = joined(bot, user_id)
    if not is_joined:
        return bot.send_message(
            chat_id,
            "⚠️ Bergabunglah ke semua channel terlebih dahulu, lalu tekan tombol verifikasi.",
            reply_markup=keyboards.join(code),
        )

    stats = repo.media_view_stats(media["id"])
    stats["title"] = html.escape(media["title"])
    stats["category"] = html.escape(media["category"])
    info = bot.send_message(chat_id, "⏳ Menyiapkan video...")
    try:
        sent = _safe_send_media(bot, chat_id, media, fmt_vars=stats)
    except Exception as exc:
        log.exception("Gagal mengirim media %s ke user %s", media["id"], user_id)
        try:
            bot.delete_message(chat_id, info.message_id)
        except Exception:
            pass
        log_service.send(
            bot,
            "❌ Pengiriman media gagal",
            f"Media ID: {media['id']}\nUser ID: {user_id}\nError: {exc}",
        )
        return bot.send_message(chat_id, "❌ Video gagal dikirim. Silakan coba lagi beberapa saat.")

    try:
        bot.delete_message(chat_id, info.message_id)
    except Exception:
        pass
    repo.add_view(media["id"], user_id)
    schedule_delete(bot, chat_id, sent.message_id, settings.auto_delete_seconds)
    return sent


def _private_only(message) -> bool:
    return getattr(message.chat, "type", "private") == "private"


def register(bot):
    @bot.message_handler(commands=["start"])
    def start(message):
        if not _private_only(message):
            return bot.reply_to(message, "Silakan gunakan bot melalui chat pribadi.")
        name = message.from_user.first_name or "User"
        repo.upsert_user(message.from_user.id, message.from_user.username or "", name)
        if _maintenance_active(message.from_user.id):
            return _maintenance_message(bot, message.chat.id)
        parts = message.text.split(maxsplit=1)
        if len(parts) > 1:
            return send_media(bot, message.chat.id, message.from_user.id, parts[1].strip())

        if message.from_user.id in settings.admin_ids:
            return bot.send_message(
                message.chat.id,
                "👑 <b>Panel Admin VIRALINMAS MEDIA</b>\n\nPilih menu:",
                parse_mode="HTML",
                reply_markup=keyboards.admin_home_reply(),
            )

        template = repo.setting("welcome_text")
        username = message.from_user.username
        username_text = (
            f"@{html.escape(username)}"
            if username
            else "<i>Tidak memiliki username</i>"
        )
        start_time = datetime.now(ZoneInfo("Asia/Jakarta")).strftime(
            "%d-%m-%Y %H:%M:%S WIB"
        )
        user_row = repo.user(message.from_user.id)
        joined_at = "–"
        if user_row and user_row["joined_at"]:
            try:
                from datetime import datetime as _dt
                joined_at = _dt.strptime(
                    user_row["joined_at"], "%Y-%m-%d %H:%M:%S"
                ).strftime("%d-%m-%Y")
            except ValueError:
                joined_at = user_row["joined_at"]
        total_users = repo.user_count()
        try:
            text = template.format(
                name=html.escape(name),
                username=username_text,
                user_id=message.from_user.id,
                start_time=start_time,
                joined_at=joined_at,
                total_users=total_users,
            )
        except (KeyError, ValueError):
            log.warning("Template welcome tidak valid; memakai fallback")
            text = f"Halo, <b>{html.escape(name)}</b>! 👋"
        bot.send_message(message.chat.id, text, parse_mode="HTML", reply_markup=keyboards.welcome())

    @bot.callback_query_handler(func=lambda call: call.data.startswith("verify:"))
    def verify(call):
        try:
            bot.answer_callback_query(call.id)
        except Exception:
            pass
        return send_media(bot, call.message.chat.id, call.from_user.id, call.data.split(":", 1)[1])

    @bot.message_handler(commands=["search"])
    def search(message):
        if not _private_only(message):
            return bot.reply_to(message, "Silakan gunakan pencarian melalui chat pribadi.")
        repo.upsert_user(
            message.from_user.id,
            message.from_user.username or "",
            message.from_user.first_name or "",
        )
        if _maintenance_active(message.from_user.id):
            return _maintenance_message(bot, message.chat.id)
        user = repo.user(message.from_user.id)
        if user and user["is_banned"]:
            return bot.reply_to(message, "⛔ Akses Anda diblokir admin.")
        query = message.text.partition(" ")[2].strip()
        if not query:
            return bot.reply_to(message, "Gunakan: <code>/search judul</code>", parse_mode="HTML")

        rows = repo.search_media(query)
        if not rows:
            return bot.reply_to(message, "Tidak ada media yang cocok.")

        username = bot.get_me().username
        text = "🔎 <b>Hasil pencarian:</b>\n\n" + "\n".join(
            f'• <a href="https://t.me/{username}?start={row["code"]}">{html.escape(row["title"])}</a> '
            f'— <i>{html.escape(row["category"])}</i>'
            for row in rows
        )
        return bot.reply_to(
            message,
            text,
            parse_mode="HTML",
            disable_web_page_preview=True,
        )

