# retoor <retoor@molodetz.nl>

import asyncio
import hashlib
import logging
import random
import re
import time
from datetime import datetime
from typing import Any, Optional

from faker import Faker

from devplacepy.services.bot.browser import BotBrowser
from devplacepy.services.bot.config import (
    COMMENT_COOLDOWN_MAX_SECONDS,
    COMMENT_COOLDOWN_MIN_SECONDS,
    FEED_TOPICS,
    GIST_LANGUAGES,
    MAX_SIBLING_COMMENTS,
    MAX_THREAD_REPLIES,
    MENTION_REPLIES_PER_SESSION,
    NOTIFICATION_CHECK_PROB,
    PERSONAS,
    PROJECT_STATUSES,
    PROJECT_TYPES,
    REACT_RATE_DEFAULT,
    REACT_RATES,
    SEARCH_TERMS,
    SESSION_COMMENT_CAP_MAX,
    SESSION_COMMENT_CAP_MIN,
    SIBLING_SNIPPET_LEN,
    USER_AGENTS,
    VIEWPORTS,
    persona_article_score,
    pick_category,
)
from devplacepy.services.bot.handles import make_handle
from devplacepy.services.bot.llm import LLMClient
from devplacepy.services.bot.news_fetcher import NewsFetcher
from devplacepy.services.bot.registry import ArticleRegistry
from devplacepy.services.bot.runtime import BotRuntimeConfig
from devplacepy.services.bot.state import BotState
from devplacepy.services.bot.agent import BotAgentMixin
from devplacepy.services.bot.auth import BotAuthMixin
from devplacepy.services.bot.browse import BotBrowseMixin
from devplacepy.services.bot.engage import BotEngageMixin
from devplacepy.services.bot.helpers import BotHelpersMixin
from devplacepy.services.bot.human import BotHumanMixin
from devplacepy.services.bot.loop import BotLoopMixin
from devplacepy.services.bot.posting import BotPostingMixin
from devplacepy.services.bot.social import BotSocialMixin

logger = logging.getLogger(__name__)


class DevPlaceBot(
    BotHelpersMixin,
    BotAuthMixin,
    BotHumanMixin,
    BotAgentMixin,
    BotEngageMixin,
    BotPostingMixin,
    BotSocialMixin,
    BotBrowseMixin,
    BotLoopMixin,
):
    def __init__(self, cfg: BotRuntimeConfig, on_event=None, slot: int = 0):
        self.cfg = cfg
        self.base_url = cfg.base_url
        self.state_path = cfg.state_path
        self.on_event = on_event
        self._slot = slot
        self.state = BotState.load(cfg.state_path)
        if not self.state.persona:
            self.state.persona = random.choice(PERSONAS)
        self._gateway_fallback_key = cfg.api_key
        self.llm = LLMClient(
            self.state.account_api_key or cfg.api_key,
            cfg.api_url,
            cfg.model,
            cfg.input_cost_per_1m,
            cfg.output_cost_per_1m,
            gist_min_lines=cfg.gist_min_lines,
        )
        self.llm.total_cost = self.state.total_cost
        self.llm.total_calls = self.state.total_calls
        self.llm.total_in_tokens = self.state.total_in_tokens
        self.llm.total_out_tokens = self.state.total_out_tokens
        self.news = NewsFetcher(cfg.news_api)
        self.registry = ArticleRegistry(
            cfg.registry_path, cfg.max_per_article, cfg.article_ttl_days
        )
        self._pause_min = min(cfg.action_pause_min, cfg.action_pause_max)
        self._pause_max = max(cfg.action_pause_min, cfg.action_pause_max)
        self._break_scale = max(0.1, cfg.break_scale)
        self._startup_jitter = max(0, cfg.startup_jitter_seconds)
        self._ai_decisions = cfg.ai_decisions
        self._decision_temperature = cfg.decision_temperature
        self.faker = Faker()
        if not self.state.user_agent:
            self.state.user_agent = random.choice(USER_AGENTS)
        if not self.state.viewport:
            self.state.viewport = random.choice(VIEWPORTS)
        self.b = BotBrowser(
            headless=cfg.headless,
            user_agent=self.state.user_agent,
            viewport=self.state.viewport,
        )
        self._session_comments = 0
        self._session_comment_cap = 0
        self._session_mention_replies = 0
        self._profile_verified = False
        self._post_cache: list[tuple[str, str, str, str, str]] = []
        self._project_cache: list[tuple[str, str]] = []
        self._issue_cache: list[tuple[str, str]] = []
        self._session_start_cost: float = 0.0
        self._session_start_calls: int = 0
        self._session_history: list[str] = []
        self._session_energy: float = 0.5
        self._session_stop_after: int = 0
