#!/usr/bin/env python3
"""Entry point for TSSBOT. Connects to Discord and idles until commands land."""
import asyncio
import logging
import os
import signal
import sys
from pathlib import Path

# Make TSSBOT root and BOTS/SHARED importable.
_HERE = Path(__file__).resolve().parent
sys.path.insert(0, str(_HERE))
sys.path.insert(0, str(_HERE.parent / "SHARED"))

import discord
from discord.ext import commands
from dotenv import load_dotenv

load_dotenv(dotenv_path=_HERE / ".env")

# Imported after load_dotenv so env vars are available.
from BOT.storage import init_tss_dbs, STORAGE_DIR  # noqa: E402
from BOT.autologging import set_bot as set_autolog_bot  # noqa: E402
from BOT.commands import setup_commands  # noqa: E402
from tss_ws import listen, _handle_game  # noqa: E402

logging.basicConfig(
    level=logging.INFO,
    format="[%(asctime)s] [%(levelname)s] [tssbot] %(message)s",
    datefmt="%Y-%m-%d %H:%M:%S",
)
log = logging.getLogger("tssbot")


def _handle_signal(signum, _frame):
    log.info(f"received signal {signum}, exiting")
    sys.exit(0)


TOKEN = os.environ.get("DISCORD_KEY", "").strip()

intents = discord.Intents.default()
intents.message_content = False
intents.reactions = True
intents.messages = True


class TSSBot(commands.Bot):
    async def setup_hook(self) -> None:
        # Register the client so the autolog matcher can post, wire up the
        # slash commands, and push them to Discord.
        set_autolog_bot(self)
        await setup_commands(self)
        try:
            synced = await self.tree.sync()
            log.info("synced %d slash command(s)", len(synced))
        except Exception as exc:
            log.error("slash command sync failed: %s", exc)


bot = TSSBot(command_prefix="!", intents=intents)


async def _ws_task_loop() -> None:
    """Run the TSS WS listener forever, restarting on any error."""
    while True:
        try:
            await listen(_handle_game)
        except Exception as exc:
            log.error(f"TSS WS listener crashed: {exc} — restarting in 10s")
            await asyncio.sleep(10)


def _write_guild_report() -> None:
    """Write TSSBOT's own guild list to the shared storage volume.

    Uses a TSS-specific filename so it does not clobber SREBOT's
    SREBOT_GUILDS.txt, which lives on the same STORAGE_VOL_PATH volume.
    """
    out_path = STORAGE_DIR / "TSSBOT_GUILDS.txt"
    with out_path.open("w", encoding="utf-8") as f:
        f.write(f"We have logged in as {bot.user} in the following Guilds:\n\n")
        for guild in bot.guilds:
            created = guild.created_at.strftime("%Y-%m-%d")
            f.write(
                f" - {guild.name} (id: {guild.id}) | Members: {guild.member_count} | Created: {created}\n"
            )
    log.info(f"Guild report written to {out_path.resolve()}")


async def _refresh_presence() -> None:
    """Update the bot's Discord presence to show the current guild count."""
    guild_total = len(bot.guilds)
    await bot.change_presence(
        activity=discord.Activity(
            type=discord.ActivityType.playing,
            name=f"Playing TSS in {guild_total} servers!",
        )
    )


@bot.event
async def on_guild_join(guild):
    log.info(f"joined guild: {guild.name} (id: {guild.id})")
    log.info(f"updated total guilds: {len(bot.guilds)}")
    _write_guild_report()
    await _refresh_presence()


@bot.event
async def on_guild_remove(guild):
    log.info(f"removed from guild: {guild.name} (id: {guild.id})")
    log.info(f"updated total guilds: {len(bot.guilds)}")
    _write_guild_report()
    await _refresh_presence()


@bot.event
async def on_ready():
    log.info(f"logged in as {bot.user} (id={bot.user.id if bot.user else '?'})")
    log.info(f"connected to {len(bot.guilds)} guild(s)")
    _write_guild_report()
    await _refresh_presence()
    asyncio.create_task(_ws_task_loop())


if __name__ == "__main__":
    signal.signal(signal.SIGTERM, _handle_signal)
    signal.signal(signal.SIGINT, _handle_signal)
    if not TOKEN:
        log.error("DISCORD_KEY not set in TSSBOT/.env — aborting")
        sys.exit(1)
    try:
        asyncio.run(init_tss_dbs())
    except Exception as e:
        log.error(f"failed to initialise TSS databases: {e}")
        sys.exit(1)
    bot.run(TOKEN, log_handler=None)
