import discord
from discord.ext import commands
from discord import FFmpegPCMAudio, PCMVolumeTransformer, VoiceProtocol, Member
from discord.ext.commands import Context
from discord.ext.commands import Bot
from extensions.tts._kakao import KakaoOpenAPI
from app.controller.logger import Logger
from io import BytesIO
from tempfile import TemporaryFile
from typing import Optional


def blockJam_mini(ctx: Context):
    return ctx.message.author.id != <PASSWORD>


class TextToSpeech(commands.Cog):
    def __init__(self, bot: Bot):
        self.bot = bot
        self.voice = None
        self.open_api = KakaoOpenAPI()

    @Logger.set()
    def is_joined(self, member: Member):
        if not member.voice:
            raise

        return self.voice and self.voice.channel.id == member.voice.channel.id

    @Logger.set()
    async def join(self, member: discord.Member):
        # Joining the already joined channel is a NOP.
        if self.is_joined(member):
            return

        channel = member.voice.channel
        try:
            if self.voice.is_playing():
                raise

            await self.voice.move_to(channel)
        except AttributeError:
            self.voice = await channel.connect()
            
    @Logger.set()
    async def _text_to_speech(self, source, ctx: Context):
        rep = self.open_api.speak_data_generator(source)
        byt = await self.open_api.text_to_speech(rep)
        data = BytesIO(byt)
        data.seek(0)
        with TemporaryFile() as file:
            file.write(data.read())
            file.seek(0)
            if not self.voice.is_playing():
                Logger.generate_log().info("O")
                self.voice.play(PCMVolumeTransformer(FFmpegPCMAudio(source=file, pipe=True), volume=150), after=file.close())
            else:
                file.close()
                Logger.generate_log().info("X")
                await ctx.send(f"{ctx.author.display_name}님 죄송하지만 TTS 재생 중에 TTS 명령어를 사용할 수 없습니다.", delete_after=60)


    @commands.command(name="tts", aliases=["t", "-", "=", "#", "%", "*", "`"])
    @commands.check(blockJam_mini)
    async def talk(self, ctx: Context, *, text: str):
        await self.join(ctx.author)
        await self._text_to_speech(f"{ctx.author.display_name}님의 메시지. {text}", ctx)


    @commands.command("disconnect")
    @commands.check(blockJam_mini)
    async def bye(self, ctx: Context):
        if not self.is_joined(ctx.author):
            return

        if self.voice.is_playing():
            raise

        await self.voice.disconnect()
        self.voice = None


def setup(bot: Bot):
    bot.add_cog(TextToSpeech(bot))

import discord
from discord.ext import commands
from discord import FFmpegPCMAudio, PCMVolumeTransformer, VoiceProtocol, Member
from discord.ext.commands import Context
from discord.ext.commands import Bot
from extensions.tts._kakao import KakaoOpenAPI
from app.controller.logger import Logger
from io import BytesIO
from tempfile import TemporaryFile
from typing import Optional


def blockJam_mini(ctx: Context):
    return ctx.message.author.id != <PASSWORD>


class TextToSpeech(commands.Cog):
    def __init__(self, bot: Bot):
        self.bot = bot
        self.voice = None
        self.open_api = KakaoOpenAPI()

    @Logger.set()
    def is_joined(self, member: Member):
        if not member.voice:
            raise

        return self.voice and self.voice.channel.id == member.voice.channel.id

    @Logger.set()
    async def join(self, member: discord.Member):
        # Joining the already joined channel is a NOP.
        if self.is_joined(member):
            return

        channel = member.voice.channel
        try:
            if self.voice.is_playing():
                raise

            await self.voice.move_to(channel)
        except AttributeError:
            self.voice = await channel.connect()
            
    @Logger.set()
    async def _text_to_speech(self, source, ctx: Context):
        rep = self.open_api.speak_data_generator(source)
        byt = await self.open_api.text_to_speech(rep)
        data = BytesIO(byt)
        data.seek(0)
        with TemporaryFile() as file:
            file.write(data.read())
            file.seek(0)
            if not self.voice.is_playing():
                Logger.generate_log().info("O")
                self.voice.play(PCMVolumeTransformer(FFmpegPCMAudio(source=file, pipe=True), volume=150), after=file.close())
            else:
                file.close()
                Logger.generate_log().info("X")
                await ctx.send(f"{ctx.author.display_name}님 죄송하지만 TTS 재생 중에 TTS 명령어를 사용할 수 없습니다.", delete_after=60)


    @commands.command(name="tts", aliases=["t", "-", "=", "#", "%", "*", "`"])
    @commands.check(blockJam_mini)
    async def talk(self, ctx: Context, *, text: str):
        await self.join(ctx.author)
        await self._text_to_speech(f"{ctx.author.display_name}님의 메시지. {text}", ctx)


    @commands.command("disconnect")
    @commands.check(blockJam_mini)
    async def bye(self, ctx: Context):
        if not self.is_joined(ctx.author):
            return

        if self.voice.is_playing():
            raise

        await self.voice.disconnect()
        self.voice = None


def setup(bot: Bot):
    bot.add_cog(TextToSpeech(bot))

# Joining the already joined channel is a NOP.