import aiohttp
import asyncio
import os
import uuid
import tempfile
from typing import List, Dict, Any

from pydantic import BaseModel


class AlignmentData(BaseModel):
    word: str
    start: float
    end: float

    def to_dict(self) -> dict:
        return {
            "word": self.word,
            "alignedWord": self.word,
            "startTime": self.start,
            "endTime": self.end,
            "hasFailedAlignment": False,
        }


class CharacterAITTS:
    def __init__(self):
        self.api_url = "https://yakova-embedding.hf.space"
        self.dir = str(tempfile.mkdtemp())
        self.descript = "https://yakova-embedding.hf.space"
        self.headers = {"Connection": "keep-alive", "Content-Type": "application/json"}

    async def _make_transcript(self, links, text):

        data = {"audio_url": links, "text": text, "file_extenstion": ".mp3"}
        response_data = await self._make_request(
            "post", "descript_transcript", json=data, external=self.descript
        )
        if not response_data:
            data["audio_url"] = data["audio_url"][0]
            print(data)
            response_data = await self.aligner(
                "post",
                "align/url",
                json=data,
            )
            print(response_data)
            response_data = self.process_alignments(
                data=response_data["alignment"], offset=0
            )
        return response_data

    def process_alignments(
        self, data: List[Dict[str, Any]], offset: float = 0
    ) -> List[Dict[str, Any]]:
        alignments = [AlignmentData(**item) for item in data]
        return [alignment.to_dict() for alignment in alignments]

    async def aligner(
        self,
        method,
        endpoint,
        json=None,
        external="https://yakova-aligner.hf.space/align/url",
    ):
        async with aiohttp.ClientSession() as session:
            if external:
                url = f"{external}"
            else:
                url = f"{self.api_url}/{endpoint}"
            async with getattr(session, method)(url=url, json=json) as response:
                return await response.json()

    async def _make_request(self, method, endpoint, json=None, external=None):
        async with aiohttp.ClientSession() as session:
            if external:
                url = f"{external}/{endpoint}"
            else:
                url = f"{self.api_url}/{endpoint}"
            async with getattr(session, method)(url=url, json=json) as response:
                return await response.json()

    async def say(self, text, speaker=None):

        data = {"text": text, "voice": speaker}

        response_data = await self._make_request("post", "cai_tts", json=data)
        # print(response_data)
        audio_url = response_data["audio"]
        temp = await self.download_file(audio_url)
        return audio_url, temp

    async def download_file(self, url):
        filename = str(uuid.uuid4()) + ".mp3"
        os.makedirs(self.dir, exist_ok=True)
        save_path = os.path.join(self.dir, filename)
        async with aiohttp.ClientSession() as session:
            async with session.get(url) as response:
                if response.status == 200:
                    with open(save_path, "wb") as file:
                        while True:
                            chunk = await response.content.read(1024)
                            if not chunk:
                                break
                            file.write(chunk)

        return save_path


# # Usage
# async def main():
#     tts = CharacterAITTS()
#     url, temp = await tts.say(
#         "Did you know that you don't have the balls to talk to me"
#     )
#     tranny = await tts._make_transcript(
#         links=[url], text="Did you know that you don't have the balls to talk to me"
#     )
#     print(tranny)


# # Run the main function
# asyncio.run(main())