"""
MAX Web ↔ Telegram Bridge
Мониторит личные сообщения в MAX Web через Playwright и пересылает их в Telegram.
Ответы из Telegram отправляются обратно в MAX.
"""

import asyncio
import logging
import os
import json
from datetime import datetime
from pathlib import Path

from playwright.async_api import async_playwright, Page, BrowserContext
from telegram import Update, Bot
from telegram.ext import Application, MessageHandler, filters, ContextTypes

# ─── Настройки ────────────────────────────────────────────────────────────────
from config import (
    TELEGRAM_BOT_TOKEN,
    TELEGRAM_CHAT_ID,
    MAX_PHONE,
    MAX_PASSWORD,
    POLL_INTERVAL,
    SESSION_FILE,
)

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s [%(levelname)s] %(message)s",
)
log = logging.getLogger(__name__)

MAX_URL = "https://web.max.ru"

# Хранилище: telegram_message_id → {"chat_name": ..., "chat_index": ...}
reply_map: dict[int, dict] = {}

# Последние известные сообщения по чату (chat_name → последний текст+отправитель)
seen_messages: dict[str, str] = {}

# Глобальный объект бота
tg_bot: Bot = None


# ─── Playwright: логин и мониторинг ───────────────────────────────────────────

async def save_session(context: BrowserContext):
    storage = await context.storage_state()
    Path(SESSION_FILE).write_text(json.dumps(storage))
    log.info("Сессия сохранена.")


async def login_max(page: Page):
    """Авторизация в MAX Web через QR-код."""
    log.info("Открываю MAX Web...")
    await page.goto(MAX_URL, wait_until="networkidle")
    await page.wait_for_timeout(2000)

    log.warning("📱 Отсканируйте QR-код в браузере через приложение MAX на телефоне!")
    log.warning("⏳ У вас 120 секунд...")

    # Ждём пока появятся чаты (признак успешного входа)
    try:
        await page.wait_for_selector(
            '[class*="ConversationItem"], [class*="chatItem"], [class*="dialog"], '
            '[class*="conversation"], [class*="chat-list"]',
            timeout=120000
        )
        log.info("✅ Вход выполнен успешно!")
    except Exception:
        log.warning("Чаты не появились за 120 сек — возможно вход не выполнен.")

    log.info("Логин завершён.")


async def get_chats(page: Page) -> list[dict]:
    """Возвращает список чатов из левой панели."""
    await page.wait_for_timeout(1000)

    chats = await page.evaluate("""
        () => {
            const items = [];
            // Перебираем все элементы списка чатов
            const els = document.querySelectorAll('.cell.svelte-q2jdqb');
            els.forEach((el, idx) => {
                const nameEl = el.querySelector('.title, .name, span');
                const msgEl = el.querySelector('.subtitle, .message, .preview');
                const unreadEl = el.querySelector('.badgeIcon .text, [class*="badgeIcon"] [class*="text"]');
                const unreadCount = unreadEl ? parseInt(unreadEl.innerText.trim()) || 0 : 0;
                const isMuted = !!el.querySelector('.iconMute');
                items.push({
                    index: idx,
                    name: nameEl ? nameEl.innerText.trim() : `Чат ${idx}`,
                    lastMessage: msgEl ? msgEl.innerText.trim() : '',
                    hasUnread: unreadCount > 0,
                    unreadCount: unreadCount,
                    isMuted: isMuted,
                });
            });
            return items;
        }
    """)
    return chats


async def open_chat(page: Page, index: int):
    """Открывает чат по индексу."""
    els = await page.query_selector_all('.cell.svelte-q2jdqb')
    if index < len(els):
        await els[index].click()
        await page.wait_for_timeout(1500)


async def get_last_message(page: Page) -> tuple[str, str]:
    """Возвращает (отправитель, текст) последнего входящего сообщения."""
    result = await page.evaluate("""
        () => {
            const msgs = document.querySelectorAll('.bubbleContent.svelte-1htnb3l');
            // Берём последнее сообщение
            const last = msgs[msgs.length - 1];
            if (!last) return ['', ''];
            const senderEl = last.querySelector('[class*="sender"], [class*="author"], [class*="name"]');
            const textEl = last.querySelector('[class*="text"], [class*="body"], [class*="content"]');
            return [
                senderEl ? senderEl.innerText.trim() : 'Собеседник',
                textEl ? textEl.innerText.trim() : ''
            ];
        }
    """)
    return result[0], result[1]


async def send_message_in_chat(page: Page, text: str):
    """Отправляет сообщение в открытый чат."""
    input_el = page.locator('.input.svelte-nwz8cp div[contenteditable="true"], div[contenteditable="true"]').first
    await input_el.click()
    await input_el.fill(text)
    await page.keyboard.press("Enter")
    await page.wait_for_timeout(500)
    log.info(f"Сообщение отправлено в MAX: {text[:50]}")


# ─── Telegram: получение ответов ──────────────────────────────────────────────

async def tg_reply_handler(update: Update, context: ContextTypes.DEFAULT_TYPE):
    """Обрабатывает ответы пользователя в Telegram."""
    msg = update.message
    if not msg:
        return

    # Принимаем только от нашего chat_id
    if str(msg.chat_id) != str(TELEGRAM_CHAT_ID):
        return

    # Должно быть reply на наше сообщение
    if not msg.reply_to_message:
        await msg.reply_text("↩️ Чтобы ответить — используйте Reply на нужное сообщение.")
        return

    original_id = msg.reply_to_message.message_id
    if original_id not in reply_map:
        await msg.reply_text("❓ Не могу найти чат для этого сообщения.")
        return

    chat_info = reply_map[original_id]
    reply_text = msg.text

    log.info(f"Ответ из Telegram → чат '{chat_info['chat_name']}': {reply_text[:50]}")

    # Ставим задачу в очередь для Playwright
    context.bot_data["pending_replies"].append({
        "chat_index": chat_info["chat_index"],
        "chat_name": chat_info["chat_name"],
        "text": reply_text,
    })

    await msg.reply_text(f"✅ Отправляю в «{chat_info['chat_name']}»...")


# ─── Основной цикл мониторинга ────────────────────────────────────────────────

async def monitor_loop(page: Page, bot: Bot, pending_replies: list):
    """Основной цикл: уведомляет когда счётчик непрочитанных вырос."""
    global seen_messages

    # Предыдущие счётчики непрочитанных: chat_name → int
    prev_unread: dict[str, int] = {}

    while True:
        try:
            # Сначала обрабатываем ответы из Telegram
            while pending_replies:
                reply = pending_replies.pop(0)
                log.info(f"Открываю чат '{reply['chat_name']}' для отправки ответа...")
                await open_chat(page, reply["chat_index"])
                await send_message_in_chat(page, reply["text"])

            # Читаем список чатов
            chats = await get_chats(page)
            if not chats:
                log.warning("Чаты не найдены — возможно, страница не загрузилась.")
                await page.reload()
                await page.wait_for_timeout(3000)
                await asyncio.sleep(POLL_INTERVAL)
                continue

            for chat in chats:
                chat_name = chat["name"]
                cur_count = chat.get("unreadCount", 0)
                prev_count = prev_unread.get(chat_name, 0)

                # Уведомляем только если счётчик ВЫРОС
                if chat.get("isMuted"):
                    prev_unread[chat_name] = cur_count
                    continue

                if cur_count <= prev_count:
                    prev_unread[chat_name] = cur_count  # фиксируем уменьшение (прочитали)
                    continue

                log.info(f"Новых сообщений: {prev_count} → {cur_count} в чате '{chat_name}'")
                prev_unread[chat_name] = cur_count

                # Чат НЕ открываем — сообщения остаются непрочитанными
                tg_text = f"\U0001f7e2 {chat_name}: {cur_count} новых"
                sent = await bot.send_message(
                    chat_id=TELEGRAM_CHAT_ID,
                    text=tg_text,
                    disable_notification=False,
                )
                log.info(f"Уведомление: {chat_name}: {cur_count} новых")

        except Exception as e:
            log.error(f"Ошибка в цикле мониторинга: {e}", exc_info=True)

        await asyncio.sleep(POLL_INTERVAL)


def escape_md(text: str) -> str:
    """Экранирует спецсимволы MarkdownV2."""
    for ch in r"\_*[]()~`>#+-=|{}.!":
        text = text.replace(ch, f"\\{ch}")
    return text


# ─── Запуск ───────────────────────────────────────────────────────────────────

async def main():
    global tg_bot

    pending_replies = []

    # Telegram Bot
    tg_app = Application.builder().token(TELEGRAM_BOT_TOKEN).build()
    tg_app.bot_data["pending_replies"] = pending_replies
    tg_app.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, tg_reply_handler))

    tg_bot = tg_app.bot
    await tg_bot.send_message(TELEGRAM_CHAT_ID, "🚀 MAX Bridge запущен! Мониторю сообщения...")

    # Playwright
    async with async_playwright() as pw:
        # Пробуем загрузить сохранённую сессию
        launch_kwargs = {"headless": True}  # headless=True после настройки

        browser = await pw.chromium.launch(**launch_kwargs)

        if Path(SESSION_FILE).exists():
            log.info("Загружаю сохранённую сессию...")
            storage = json.loads(Path(SESSION_FILE).read_text())
            context = await browser.new_context(storage_state=storage)
        else:
            context = await browser.new_context()

        page = await context.new_page()

        # Логин
        await page.goto(MAX_URL, wait_until="networkidle")
        await page.wait_for_timeout(3000)

        # Проверяем по localStorage — там хранится токен авторизации
        is_logged_in = await page.evaluate("""
            () => {
                const auth = localStorage.getItem('__oneme_auth');
                if (!auth) return false;
                try {
                    const parsed = JSON.parse(auth);
                    return !!parsed.token;
                } catch(e) {
                    return false;
                }
            }
        """)

        if not is_logged_in:
            log.info("Сессия не найдена — нужен логин через QR.")
            await login_max(page)
            await save_session(context)
        else:
            log.info("✅ Сессия активна, логин не нужен. Начинаю мониторинг...")

        # Запускаем Telegram polling и мониторинг параллельно
        async with tg_app:
            await tg_app.start()
            await tg_app.updater.start_polling()

            await monitor_loop(page, tg_bot, pending_replies)

            await tg_app.updater.stop()
            await tg_app.stop()

        await browser.close()


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