# froscord/voice/core.py
import asyncio
import discord
from discord.ext import commands

from .panel import VoicePanel
from .commands import VCCommands


class VoiceSystem:
    def __init__(
        self,
        bot: commands.Bot,
        join_channel: str,
        category: str,
        user_limit: int = 0,
        panel: bool = True,
    ):
        self.bot = bot
        self.join_channel = join_channel
        self.category_name = category
        self.user_limit = user_limit
        self.panel_enabled = panel

        # system state
        self.enabled = False
        self.trigger_vc_id: int | None = None
        self.category_id: int | None = None

        # vc_id -> {"owner": user_id, "message": message_id}
        self._vcs: dict[int, dict] = {}

        bot.add_listener(self._on_voice_state_update, "on_voice_state_update")
        self.bot.tree.add_command(VCCommands(self))

    # ───────────────── VOICE EVENT ─────────────────

    async def _on_voice_state_update(self, member, before, after):
        if (
            self.enabled
            and after.channel
            and after.channel.id == self.trigger_vc_id
        ):
            await self._create_vc(member)

        if before.channel and before.channel.id in self._vcs:
            await self._handle_leave(before.channel, member)

    # ───────────────── SETUP ─────────────────

    async def setup(self, guild: discord.Guild):
        if self.enabled:
            return

        category = discord.utils.get(
            guild.categories, name=self.category_name
        )
        if not category:
            category = await guild.create_category(self.category_name)

        self.category_id = category.id

        trigger_vc = await guild.create_voice_channel(
            name=self.join_channel,
            category=category
        )

        self.trigger_vc_id = trigger_vc.id
        self.enabled = True

    # ───────────────── SAFE MOVE (RISHIKA-STYLE) ─────────────────

    async def _safe_move(self, member: discord.Member, vc: discord.VoiceChannel):
        for _ in range(10):  # ~1 second max
            if member.voice and member.voice.channel:
                break
            await asyncio.sleep(0.1)

        try:
            await member.move_to(vc)
        except Exception:
            pass

    # ───────────────── CREATE VC ─────────────────

    async def _create_vc(self, member):
        for data in self._vcs.values():
            if data["owner"] == member.id:
                return

        guild = member.guild

        category = guild.get_channel(self.category_id)
        if not category:
            category = await guild.create_category(self.category_name)
            self.category_id = category.id

        vc = await guild.create_voice_channel(
            name=f"🔊 {member.display_name}'s VC",
            category=category,
            user_limit=self.user_limit
        )

        await self._safe_move(member, vc)

        self._vcs[vc.id] = {"owner": member.id, "message": None}

        if self.panel_enabled:
            panel = VoicePanel(self, vc.id)
            msg = await vc.send(embed=panel.build_embed(), view=panel)
            self._vcs[vc.id]["message"] = msg.id

    # ───────────────── LEAVE / OWNER TRANSFER ─────────────────

    async def _handle_leave(self, channel: discord.VoiceChannel, member):
        data = self._vcs.get(channel.id)
        if not data:
            return

        if member.id == data["owner"]:
            if channel.members:
                new_owner = channel.members[0]
                data["owner"] = new_owner.id
                await channel.edit(
                    name=f"🔊 {new_owner.display_name}'s VC"
                )
            else:
                await channel.delete()
                self._vcs.pop(channel.id, None)

    # ───────────────── API ─────────────────

    def get_vc_data(self, vc_id: int):
        return self._vcs.get(vc_id)

    def remove_vc(self, vc_id: int):
        self._vcs.pop(vc_id, None)

    async def refresh_panel(self, interaction, vc_id: int):
        data = self._vcs.get(vc_id)
        if not data:
            return

        vc = interaction.guild.get_channel(vc_id)
        if not vc:
            return

        msg = await interaction.channel.fetch_message(data["message"])

        panel = VoicePanel(self, vc_id)
        embed = panel.build_embed()
        if embed:
            await msg.edit(embed=embed, view=panel)