import os, signal, asyncio, pathlib
import discord
from discord.ext import commands
from dotenv import load_dotenv

from data_manager import DataManager
from modules.common.settings import cfg as cfg_helper
from modules.common.boot_notice import post_boot_notice

# Version consists of:
# Major.Enhancement.Minor.Patch.Test  (Test is alphanumeric; doesn’t trigger auto update)
VERSION = "0.4.2.1.a1"

# ---------- Env loading ----------

load_dotenv()

def _get_env(name: str, default: str = "") -> str:
    v = os.getenv(name, "")
    return (v or "").strip().strip('"').strip("'") or default

TOKEN = _get_env("DISCORD_TOKEN")
DATA_FILE = _get_env("SHAI_DATA") or _get_env("SHAI_DATA_FILE") or "/data/data.json"

print("[Config] DISCORD_TOKEN set:", bool(TOKEN))
print("[Config] DATA_FILE:", DATA_FILE)

# ---------- Discord intents ----------

intents = discord.Intents.default()
intents.guilds = True
intents.members = True
intents.message_content = True
intents.reactions = True
intents.emojis_and_stickers = True
intents.voice_states = True

# ---------- Bot + DataManager ----------

if not TOKEN:
    print("[Config] WARNING: DISCORD_TOKEN is empty. The bot will fail to log in.")

bot = commands.Bot(command_prefix="!", intents=intents)

# Ensure data path exists and is seeded
os.makedirs(os.path.dirname(DATA_FILE) or ".", exist_ok=True)
if not os.path.exists(DATA_FILE):
    with open(DATA_FILE, "w", encoding="utf-8") as f:
        f.write("{}")

bot.data_manager = DataManager(DATA_FILE)

# ---------- Self-check: resolve from ENV first, then cfg_helper ----------
def _resolve_channel_id(c, key: str) -> int:
    # 1) ENV always wins
    env_key = f"SHAI_{key.upper()}"
    raw = os.getenv(env_key, "").strip().strip('"').strip("'")
    if raw.isdigit():
        return int(raw)

    # 2) Try cfg_helper (if it happens to know)
    try:
        v = int(c.int(key, 0))
        if v:
            return v
    except Exception:
        pass

    # 3) Last resort: legacy bot.config shapes
    try:
        # bot.config like dict
        v = int(getattr(c, "get", lambda *_: 0)(key, 0))
        if v:
            return v
    except Exception:
        pass

    return 0


async def _guild_selfcheck(g: discord.Guild, c):
    problems = []

    def _need_channel(id_key, *perms):
        cid = _resolve_channel_id(c, id_key)
        if not cid:
            problems.append(f"Missing config key: {id_key}")
            return

        ch = g.get_channel(cid)
        if not ch:
            problems.append(f"Channel not found: {id_key}={cid}")
            return

        me = g.me
        p = ch.permissions_for(me)
        for perm in perms:
            if not getattr(p, perm, False):
                problems.append(f"Missing permission on #{ch.name}: {perm}")

    _need_channel('mod_channel_id', 'read_messages', 'send_messages', 'add_reactions', 'read_message_history')
    _need_channel('modlog_channel_id', 'read_messages', 'send_messages')
    _need_channel('pirates_list_channel_id', 'read_messages', 'send_messages')
    _need_channel('dd_channel_id', 'read_messages', 'send_messages', 'read_message_history')

    if problems:
        print(f"[SelfCheck:{g.name}]")
        for p in problems:
            print(" -", p)

# ---------- events ----------

@bot.event
async def on_ready():
    import asyncio

    print(f"Logged in as {bot.user} (ID: {bot.user.id})")
    print("[Intents] members:", bot.intents.members,
          "/ message_content:", bot.intents.message_content,
          "/ voice_states:", bot.intents.voice_states)

    env_cfg = cfg_helper(bot)

    # Per-guild permission sanity checks (env-aware)
    try:
        await asyncio.gather(*[_guild_selfcheck(g, env_cfg) for g in bot.guilds])
    except Exception as e:
        print("[SelfCheck] failed:", repr(e))

    # ---------- Slash command scope & sync ----------
    #
    # Toggle here (or set SHAI_SLASH_GUILD_ONLY=true/false):
    guild_only = env_cfg.bool("slash_guild_only", True)

    # Choose target guilds for "instant" registration
    target_gids = set()
    for key in ("home_guild_id", "dev_guild_id"):
        val = env_cfg.get(key)
        if val:
            try:
                target_gids.add(int(val))
            except Exception:
                pass

    try:
        if guild_only and target_gids:
            print(f"[Slash] Mode: GUILD-ONLY to {sorted(target_gids)}")

            # Copy all currently-loaded global commands to each target guild
            for gid in sorted(target_gids):
                g = bot.get_guild(gid)
                if not g:
                    print(f"[Slash] Guild {gid}: not in cache; skipping copy/sync.")
                    continue
                bot.tree.copy_global_to(guild=g)
                g_cmds = await bot.tree.sync(guild=g)
                names = ", ".join(f"/{c.name}" for c in g_cmds) if g_cmds else "(none)"
                print(f"[Slash] Synced {len(g_cmds)} commands to {g.name} ({g.id}): {names}")

            # Now remove global commands so only guild-scoped remain
            bot.tree.clear_commands(guild=None)
            cleared = await bot.tree.sync()  # push empty global set (purges old global copies)
            print(f"[Slash] Cleared global commands (now {len(cleared)}).")

        else:
            print("[Slash] Mode: GLOBAL")
            # Purge any old per-guild copies in target guilds (to avoid dupes),
            # then sync globally once.
            for gid in sorted(target_gids):
                g = bot.get_guild(gid)
                if not g:
                    print(f"[Slash] Guild {gid}: not in cache; skip purge.")
                    continue
                bot.tree.clear_commands(guild=g)
                await bot.tree.sync(guild=g)
                print(f"[Slash] Purged guild-specific commands in {g.name} ({g.id}).")

            global_cmds = await bot.tree.sync()
            names = ", ".join(f"/{c.name}" for c in global_cmds) if global_cmds else "(none)"
            print(f"[Slash] Synced {len(global_cmds)} commands globally: {names}")

        # --- Always print what actually exists after sync ---
        def _fmt_cmds(cmds):
            try:
                return ", ".join(f"/{c.name}" for c in cmds) if cmds else "(none)"
            except Exception:
                return "(unreadable)"

        # Global list
        try:
            global_cmds = await bot.tree.fetch_commands()
            print(f"[Slash] Global commands ({len(global_cmds)}): {_fmt_cmds(global_cmds)}")
        except Exception as e:
            print("[Slash] Failed to fetch global commands:", repr(e))

        # Guild lists
        for gid in sorted(target_gids):
            g = bot.get_guild(gid)
            if not g:
                print(f"[Slash] Guild {gid}: not in cache; cannot fetch commands.")
                continue
            try:
                g_cmds = await bot.tree.fetch_commands(guild=g)
                print(f"[Slash] {g.name} ({g.id}) guild commands ({len(g_cmds)}): {_fmt_cmds(g_cmds)}")
            except Exception as e:
                print(f"[Slash] Failed to fetch commands for guild {gid}:", repr(e))

    except Exception as e:
        print("[Slash] Sync failed:", repr(e))

    # Post boot status message
    try:
        await post_boot_notice(bot)
    except Exception as e:
        print("[BootNotice] failed:", repr(e))

# ---------- Auto-discover extensions ----------

modules_path = pathlib.Path(__file__).parent / "modules"
extensions = []
for folder in modules_path.iterdir():
    if not folder.is_dir():
        continue
    # skip non-cog helpers under modules/common
    if folder.name == "common":
        continue
    for file in folder.glob("*.py"):
        if file.name == "__init__.py":
            continue
        extensions.append(f"modules.{folder.name}.{file.stem}")

def _install_signal_handlers(loop, bot_obj):
    def _graceful(*_):
        loop.create_task(bot_obj.close())
    for s in (signal.SIGTERM, signal.SIGINT):
        try:
            loop.add_signal_handler(s, _graceful)
        except NotImplementedError:
            pass  # Windows

async def main():
    print(f"[STARTUP] ShaiWatcher booting v{VERSION}")
    async with bot:
        for ext in extensions:
            try:
                await bot.load_extension(ext)
                print(f"[Modules] Loaded: {ext}")
            except Exception as e:
                print(f"[Modules] Failed to load {ext}:", repr(e))
        loop = asyncio.get_running_loop()
        _install_signal_handlers(loop, bot)
        await bot.start(TOKEN)

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