"""vh_probe.py — Live e2e probe для @VakHunter_bot через web.telegram.org.

Запускать на mac mini:
    PLAYWRIGHT_BROWSERS_PATH=/Users/cebers_mini/Library/Caches/ms-playwright \
        ~/.venvs/gaechkin/bin/python /tmp/vh_probe.py

Использует тест-сессию ~/.gaechkin/tg_test_session.json (юзер
Cebers_Dev_Support, TG id 8688355181 — обычный non-admin).
Прокси http://127.0.0.1:2081 (РКН-обход).

Cценарий (UX после S-серии 5f53925 + Option A 04b6684):
  1. Открыть чат через deep-link #@VakHunter_bot.
  2. Отправить /start, проверить welcome + «Жми Найти работу».
  3. Отправить быстрый поиск /search python москва → фид карточек.
  4. Прочитать тексты последних bubble-ов: карточки 🏢/💰/🏷,
     источники, префиксы 💼/🛒 (вакансия/заказ), кнопка «Подробнее».
  5. Сохранить скриншоты в /tmp/vh_audit/shots_vh/.
"""
import asyncio
import re
import sys
import time
from pathlib import Path

SESSION = "/Users/cebers_mini/.gaechkin/tg_test_session.json"
OUT = Path("/tmp/vh_audit")
OUT.mkdir(parents=True, exist_ok=True)
SHOTS = OUT / "shots_vh"
SHOTS.mkdir(exist_ok=True)
BOT = "VakHunter_bot"
PROXY = "http://127.0.0.1:2081"


async def shoot(page, name):
    p = SHOTS / f"{int(time.time())}_{name}.png"
    try:
        await page.screenshot(path=str(p), full_page=False)
    except Exception:
        pass


async def last_bubble_text(page, n=5):
    """Return the text of the last n incoming bubbles."""
    bubbles = await page.locator(".bubble.is-in .message").all()
    texts = []
    for b in bubbles[-n:]:
        try:
            texts.append(await b.inner_text())
        except Exception:
            pass
    return texts


async def click_in_latest_bubble(page, text, timeout=10000):
    """Locate the LATEST bubble that has a button with `text` and click it."""
    btns = page.locator(f'.bubble.is-in .reply-markup-button:has-text("{text}")')
    cnt = await btns.count()
    if cnt == 0:
        raise RuntimeError(f"button «{text}» not found in any bubble")
    # last one is the most recent
    await btns.nth(cnt - 1).click(timeout=timeout)


async def main():
    from playwright.async_api import async_playwright
    findings = []

    def add(name, ok, detail=""):
        findings.append((name, ok, detail))
        mark = "✅" if ok else "❌"
        print(f"{mark} {name}: {detail}", flush=True)

    async with async_playwright() as pw:
        browser = await pw.chromium.launch(
            headless=True, proxy={"server": PROXY},
        )
        context = await browser.new_context(
            storage_state=SESSION,
            viewport={"width": 1280, "height": 1100},
            locale="ru-RU",
        )
        page = await context.new_page()
        try:
            await page.goto(
                f"https://web.telegram.org/k/#@{BOT}",
                wait_until="domcontentloaded", timeout=60000,
            )
            await page.wait_for_timeout(7000)
            await shoot(page, "01_opened")

            inp = page.locator(".input-message-input").first

            # /start
            await inp.click()
            await inp.fill("/start")
            await page.keyboard.press("Enter")
            await page.wait_for_timeout(5000)
            await shoot(page, "02_after_start")
            texts = await last_bubble_text(page, 3)
            text_blob = " || ".join(texts)
            start_ok = any(
                m in text_blob for m in ("VakHunter", "вакансии", "поиск",
                                         "Найти работу", "источников")
            )
            add("/start ответ содержит маркеры", start_ok,
                f"last bubble: {text_blob[:100]!r}")
            add("welcome без «до Не активирован»",
                "до Не активирован" not in text_blob,
                "кривая склейка тарифной строки" if "до Не активирован" in text_blob else "")

            # Быстрый поиск (новый UX: меню = reply-keyboard, фид — через
            # /search <запрос> <город>; кнопочный путь покрыт vh_sub_test)
            await inp.click()
            await inp.fill("/search python москва")
            await page.keyboard.press("Enter")
            await page.wait_for_timeout(60000)  # поиск идёт по 20 площадкам,
            # часть через прокси: 15 с не хватало и проба врала «карточек 0»
            await shoot(page, "04_results")

            # Снять текст последних 5 bubble — там должны быть карточки
            texts = await last_bubble_text(page, 10)
            full_chat = "\n".join(texts)
            (OUT / "chat_after_search.txt").write_text(full_chat)

            sources_known = (
                "hh.ru", "habr", "fl.ru", "kwork", "kwork.ru", "profi.ru",
                "avito", "avito-services", "superjob", "trudvsem", "telegram",
                "rabota", "hh.by", "hh.kz", "hh.uz",
            )
            # Бот рисует источники как «Kwork», «HH.ru», «Хабр Карьера» — с заглавных.
            # Сверка в исходном регистре не находила НИ ОДНОГО и валила проверку всегда.
            chat_lc = full_chat.lower()
            uniq_sources = sorted({s for s in sources_known if s.lower() in chat_lc})
            add(f"Источники в выдаче ({len(uniq_sources)})",
                len(uniq_sources) >= 1,
                f"{uniq_sources or 'NONE'}")

            n_company = full_chat.count("🏢")
            n_salary = full_chat.count("💰")
            n_source = full_chat.count("🏷")
            cards_estimate = min(n_company, n_salary, n_source)
            add(f"Карточек в выдаче (по emoji: 🏢={n_company} 💰={n_salary} 🏷={n_source})",
                cards_estimate >= 1, f"estimate={cards_estimate}")

            # U2: карточки префиксуются 💼 (вакансия) / 🛒 (заказ)
            n_job = full_chat.count("💼")
            n_order = full_chat.count("🛒")
            add(f"UI различает Заказ/Вакансию (💼={n_job} 🛒={n_order})",
                (n_job + n_order) >= 1,
                "" if (n_job + n_order) else "NONE — префиксы не отрисованы")

            # Option A: в списке карточек по одной кнопке «🔍 Подробнее»
            buttons_count = await page.locator(
                '.bubble.is-in .reply-markup-button:has-text("Подробнее")'
            ).count()
            add(f"Кнопок «Подробнее» в чате: {buttons_count}",
                buttons_count >= 1, "")

            await shoot(page, "99_final")
        except Exception as e:
            import traceback
            traceback.print_exc()
            add("EXCEPTION", False, f"{type(e).__name__}: {e}")
            await shoot(page, "99_error")
        finally:
            await browser.close()

    passed = sum(1 for _, ok, _ in findings if ok)
    print(f"\n{'='*60}\nVH PROBE: {passed}/{len(findings)} PASS")
    print(f"shots: {SHOTS}/")
    print(f"chat dump: {OUT}/chat_after_search.txt")
    print(f"{'='*60}")
    return 0 if passed == len(findings) else 1


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