# retoor <retoor@molodetz.nl>

import asyncio
import logging
import random
from datetime import datetime

from devplacepy.services.bot.config import SEARCH_TERMS
from devplacepy.services.bot.handles import make_handle

logger = logging.getLogger(__name__)

SIGNUP_BIRTH_DATE = "1995-01-01"


class BotAuthMixin:
    def _generate_handle(self) -> str:
        return make_handle(SEARCH_TERMS.get(self.state.persona, []))

    def _next_handle(self) -> str:
        while self.state.handle_candidates:
            candidate = self.state.handle_candidates.pop(0)
            if candidate:
                return candidate
        return self._generate_handle()

    async def _ensure_auth(self) -> bool:
        b = self.b
        if not self.state.username:
            if not self.state.handle_candidates:
                self.state.handle_candidates = (
                    await self._generate(
                        self.llm.generate_handle_candidates, self.state.persona
                    )
                    or []
                )
            self.state.username = self._next_handle()
            self.state.account_api_key = ""
            self.state.email = self.faker.email()
            self.state.password = self.faker.password(length=random.randint(12, 18))
            self.state.started_at = datetime.now().isoformat()
            self._log(f"Identity: {self.state.username} / {self.state.email}")

        curl = await b.url()
        if "/feed" in curl:
            return True

        await b.goto(f"{self.base_url}/auth/login")
        curl = await b.url()
        if "/feed" in curl:
            return True

        if await b.fill("#email", self.state.email):
            await b._idle(0.2, 0.5)
            await b.fill("#password", self.state.password)
            await b._idle(0.3, 0.8)
            await b.click(".auth-submit")
            await asyncio.sleep(2)
            curl = await b.url()
            if "/feed" in curl:
                self._log("Logged in")
                return True

        self._log("Login failed, registering")
        for attempt in range(4):
            await b.goto(f"{self.base_url}/auth/signup")
            if not await b.fill("#username", self.state.username):
                return False
            await b._idle(0.2, 0.5)
            await b.fill("#email", self.state.email)
            await b._idle(0.2, 0.5)
            await b.fill("#password", self.state.password)
            await b._idle(0.2, 0.5)
            await b.fill("#confirm_password", self.state.password)
            await b._idle(0.2, 0.5)
            await b.fill("#birth_date", SIGNUP_BIRTH_DATE)
            await b._idle(0.2, 0.5)
            await b.click("#accept_terms")
            await b._idle(0.5, 1.0)
            await b.click(".auth-submit")
            await asyncio.sleep(2)
            curl = await b.url()
            if "/feed" in curl:
                self._log(f"Registered as {self.state.username}")
                return True
            if attempt >= 2:
                base = self._next_handle()
                self.state.username = f"{base}{random.randint(10, 9999)}"[:20]
            else:
                self.state.username = self._next_handle()
            self.state.account_api_key = ""
            self.state.email = self.faker.email()
            self._log(f"Signup failed, retrying as {self.state.username}")
        return False

    async def _fetch_own_profile(self) -> dict:
        if not self.state.username:
            return {}
        try:
            data = await self.b.page.evaluate(
                """async (username) => {
                    const resp = await fetch(`/profile/${username}`, {
                        headers: {Accept: 'application/json'},
                    });
                    if (!resp.ok) return null;
                    return await resp.json();
                }""",
                self.state.username,
            )
        except Exception as e:
            logger.debug("fetch own profile failed: %s", e)
            return {}
        return data if isinstance(data, dict) else {}

    async def _fetch_account_api_key(self) -> str:
        profile = await self._fetch_own_profile()
        return (profile.get("api_key") or "").strip()

    async def _adopt_account_api_key(self) -> bool:
        for attempt in range(5):
            key = await self._fetch_account_api_key()
            if key:
                if key != self.state.account_api_key:
                    self.state.account_api_key = key
                    self._save()
                    self._log("Adopted account API key for gateway calls")
                self.llm.api_key = key
                return True
            if attempt < 4:
                await asyncio.sleep(2)
        self._log("Account API key unavailable after retries")
        return False
