import time
from AbhiCalls.queue import SongQueue


class Player:
    def __init__(self, engine):
        self.engine = engine
        self.queues = {}
        self.start_time = {}

    # ==========================
    # INTERNAL QUEUE
    # ==========================
    def _queue(self, chat_id):
        return self.queues.setdefault(chat_id, SongQueue())

    # ==========================
    # CURRENT TIME
    # ==========================
    def current_time(self, chat_id):
        start = self.start_time.get(chat_id)
        if not start:
            return 0
        return max(int(time.time() - start), 0)

    # ==========================
    # PLAY
    # ==========================
    async def play(self, chat_id, song, video: bool = False):
        q = self._queue(chat_id)
        pos = q.add(song)

        print(
            f"[Player:Play] chat={chat_id} "
            f"pos={pos} video={song.is_video} title={song.title}"
        )

        if pos == 1:
            try:
                await self.engine.play(
                    chat_id,
                    song.stream,
                    video=song.is_video
                )
                self.start_time[chat_id] = time.time()

            except Exception as e:
                print(f"[Player:PlayError] {chat_id} → {e}")
                q.pop_last()
                self.start_time.pop(chat_id, None)
                raise

        return pos

    # ==========================
    # SEEK
    # ==========================
    async def seek(self, chat_id, seconds: int):
        q = self.queues.get(chat_id)

        if not q or not q.current():
            return False

        song = q.current()
        current_elapsed = self.current_time(chat_id)
        new_time = max(current_elapsed + seconds, 0)

        duration = getattr(song, "duration_sec", 0)

        if duration > 0 and new_time >= duration:
            return False

        try:
            await self.engine.play(
                chat_id,
                song.stream,
                start_time=new_time,
                video=song.is_video
            )

            self.start_time[chat_id] = time.time() - new_time
            return True

        except Exception as e:
            print(f"[Player:SeekError] {e}")
            return False

    # ==========================
    # SKIP
    # ==========================
    async def skip(self, chat_id):
        q = self.queues.get(chat_id)
        if not q:
            return None

        current = q.current()
        nxt = q.next()

        if not nxt:
            self.start_time.pop(chat_id, None)
            try:
                await self.engine.stop(chat_id)
            except Exception:
                pass
            return None

        try:
            await self.engine.play(
                chat_id,
                nxt.stream,
                video=nxt.is_video
            )
            self.start_time[chat_id] = time.time()
            print(f"[Player:Skip] next={nxt.title}")
            return nxt

        except Exception as e:
            print(f"[Player:SkipError] {e}")

            # restore state safely
            if current:
                q.items.insert(0, current)

            return None

    # ==========================
    # PREVIOUS
    # ==========================
    async def previous(self, chat_id):
        q = self.queues.get(chat_id)
        if not q:
            return None

        prev = q.previous()
        if not prev:
            return None

        try:
            await self.engine.play(
                chat_id,
                prev.stream,
                video=prev.is_video
            )
            self.start_time[chat_id] = time.time()
            return prev

        except Exception as e:
            print(f"[Player:PreviousError] {e}")
            return None

    # ==========================
    # STOP
    # ==========================
    async def stop(self, chat_id):
        if chat_id in self.queues:
            self.queues[chat_id].clear()

        self.start_time.pop(chat_id, None)

        try:
            await self.engine.stop(chat_id)
        except Exception:
            pass

    # ==========================
    # BASIC CONTROLS
    # ==========================
    async def pause(self, chat_id):
        await self.engine.pause(chat_id)

    async def resume(self, chat_id):
        await self.engine.resume(chat_id)

    async def mute(self, chat_id):
        await self.engine.mute(chat_id)

    async def unmute(self, chat_id):
        await self.engine.unmute(chat_id)

    async def volume(self, chat_id, volume: int):
        volume = max(0, min(volume, 200))
        await self.engine.change_volume(chat_id, volume)

    # ==========================
    # LOOP
    # ==========================
    def set_loop(self, chat_id, count=None):
        q = self._queue(chat_id)

        if count is None:
            q.infinite_loop = not q.infinite_loop
            return q.infinite_loop

        if count <= 0:
            return 0

        cur = q.current()
        if cur:
            cur.loop_left = max(count - 1, 0)
            return count

        return 0

    # ==========================
    # ETA
    # ==========================
    def eta(self, chat_id):
        q = self.queues.get(chat_id)
        if not q or not q.current():
            return None

        elapsed = self.current_time(chat_id)
        dur = getattr(q.current(), "duration_sec", 0)

        if dur <= 0:
            return None

        return max(dur - elapsed, 0)
