# retoor <retoor@molodetz.nl>

import asyncio
import logging
import random
import re
from typing import Optional

logger = logging.getLogger(__name__)


class BotHumanMixin:
    async def _read_like_human(self, min_s: float = 3.0, max_s: float = 90.0) -> None:
        if not self.state.reading_speed_wpm:
            self.state.reading_speed_wpm = random.randint(180, 320)
        wpm = self.state.reading_speed_wpm
        sec_per_word = 60.0 / wpm
        curl = await self.b.url()
        if "/posts/" in curl:
            body = (
                await self.b.text("article") or await self.b.text(".post-content") or ""
            )
            wc = len(body.split())
            jitter = random.uniform(0.7, 1.25)
            pause = min(max(wc * sec_per_word * jitter, min_s), max_s)
            self._log(f"Reading {wc} words ({pause:.0f}s @ {wpm}wpm)")
            scrolls = max(1, int(pause / 12))
            chunk = pause / scrolls
            for _ in range(scrolls):
                await asyncio.sleep(chunk)
                if random.random() < 0.55:
                    await self.b.scroll(random.randint(150, 450))
        else:
            await asyncio.sleep(random.uniform(1.0, 4.0))

    async def _type_like_human(self, sel: str, val: str) -> bool:
        el = self.b.page.locator(sel).first
        if await el.count() == 0:
            return False
        try:
            await el.click(timeout=3000)
            await self.b._idle(0.1, 0.3)
            await el.fill("")
            words = val.split(" ")
            for i, word in enumerate(words):
                for ch in word:
                    delay = random.randint(15, 80)
                    if ch in ".!?":
                        delay = random.randint(200, 500)
                    elif ch == ",":
                        delay = random.randint(100, 250)
                    await self.b.page.keyboard.type(ch, delay=delay)
                if i < len(words) - 1:
                    space_delay = random.randint(30, 120)
                    await self.b.page.keyboard.type(" ", delay=space_delay)
                if random.random() < 0.08:
                    await self.b._idle(0.3, 1.0)
                if (i + 1) % 5 == 0 and random.random() < 0.3:
                    await self.b._idle(0.2, 0.8)
            return True
        except Exception as e:
            logger.debug("_type_like_human failed for '%s': %s", sel, e)
            return False

    async def _fatigue_check(self, session_actions: int) -> Optional[str]:
        if session_actions < 5:
            return None
        chance = session_actions / 100.0
        if random.random() < chance:
            if session_actions < 10:
                return "casual"
            elif session_actions < 20:
                return "normal"
            else:
                return "deep"
        return None

    async def _session_type(self) -> tuple[str, int, tuple]:
        roll = random.random()
        if roll < 0.25:
            return ("lurking", random.randint(2, 5), (3600, 21600))
        elif roll < 0.60:
            return ("casual", random.randint(4, 10), (1800, 7200))
        elif roll < 0.85:
            return ("normal", random.randint(8, 18), (3600, 14400))
        else:
            return ("deep", random.randint(15, 30), (14400, 43200))

    async def _ensure_identity(self) -> None:
        if self.state.identity:
            return
        identity = await self._generate(
            self.llm.generate_identity, self.state.persona
        )
        if identity:
            self.state.identity = identity
            self._log(
                f"Identity card: {identity.get('name', '?')} ({self.state.persona})"
            )
            self._save()

    async def _page_summary(self, page: str) -> str:
        b = self.b
        title = ""
        for sel in ("h1", ".post-title", ".content-title", "title"):
            title = (await b.text(sel) or "").strip()
            if title:
                break
        summary = f'title="{title[:100]}"' if title else "no title"
        try:
            comments = await b.page.locator(".comment, .comment-item").count()
            if comments:
                summary += f", {comments} comments"
        except Exception as e:
            logger.debug("page summary count failed: %s", e)
        return summary

    async def _unread_notification_count(self) -> int:
        try:
            badge = self.b.page.locator(
                "a[data-counter='notifications'] .nav-badge[data-counter-badge]"
            ).first
            if await badge.count() == 0:
                return 0
            if await badge.get_attribute("hidden") is not None:
                return 0
            text = (await badge.inner_text() or "").strip()
            digits = re.sub(r"[^0-9]", "", text)
            return int(digits) if digits else 0
        except Exception as e:
            logger.debug("_unread_notification_count failed: %s", e)
            return 0

    async def _page_state(
        self,
        curl: str,
        page_text: str,
        *,
        did_post: bool,
        follows: int,
        gists: int,
        can_project: bool,
        can_post: bool,
        can_message: bool,
    ) -> dict:
        pages = [
            ("post", "/posts/" in curl),
            ("profile", "/profile/" in curl),
            ("news_detail", "/news/" in curl),
            ("news_list", bool(re.search(r"/news(\?|$)", curl))),
            ("project_detail", "/projects/" in curl),
            ("projects_list", bool(re.search(r"/projects(\?|$)", curl))),
            ("gist_detail", "/gists/" in curl),
            ("gists_list", bool(re.search(r"/gists(\?|$)", curl))),
            ("notifications", "/notifications" in curl),
        ]
        page = next((name for name, hit in pages if hit), "feed")
        own_post = page == "post" and await self._is_own_post()
        mentioned = own_post and f"@{self.state.username.lower()}" in page_text
        own_profile = (
            page == "profile"
            and f"/profile/{self.state.username.lower()}" in curl.lower()
        )
        return {
            "page": page,
            "url": curl,
            "visible": await self._page_summary(page),
            "own_post": own_post,
            "own_profile": own_profile,
            "mentioned": mentioned,
            "did_post": did_post,
            "follows": follows,
            "gists": gists,
            "can_project": can_project,
            "can_post": can_post,
            "can_message": can_message,
            "unread_notifications": await self._unread_notification_count(),
        }
