from __future__ import annotations

from typing import TYPE_CHECKING

from .._resource import AsyncAPIResource, SyncAPIResource
from .._types import NOT_GIVEN, NotGiven, is_given
from .._utils import strip_not_given
from ..types.create_response import CreateResponse
from ..types.generation import Generation
from ..types.speech_generate_params import VoiceSettings


class Speech(SyncAPIResource):
    def submit(
        self,
        *,
        model: str,
        input: str,
        voice: str,
        language: str | NotGiven = NOT_GIVEN,
        speed: float | NotGiven = NOT_GIVEN,
        pitch: int | NotGiven = NOT_GIVEN,
        emotion: str | NotGiven = NOT_GIVEN,
        instructions: str | NotGiven = NOT_GIVEN,
        voice_settings: VoiceSettings | NotGiven = NOT_GIVEN,
        sample_rate: int | NotGiven = NOT_GIVEN,
        format: str | NotGiven = NOT_GIVEN,
        **extra_body: object,
    ) -> CreateResponse:
        body = strip_not_given({
            "model": model,
            "input": input,
            "voice": voice,
            "language": language,
            "speed": speed,
            "pitch": pitch,
            "emotion": emotion,
            "instructions": instructions,
            "voice_settings": dict(voice_settings) if is_given(voice_settings) else voice_settings,
            "sample_rate": sample_rate,
            "format": format,
        })
        for k, v in extra_body.items():
            if is_given(v):
                body[k] = v
        return self._post("/generatespeech", cast_to=CreateResponse, body=body)

    def generate(
        self,
        *,
        model: str,
        input: str,
        voice: str,
        language: str | NotGiven = NOT_GIVEN,
        speed: float | NotGiven = NOT_GIVEN,
        pitch: int | NotGiven = NOT_GIVEN,
        emotion: str | NotGiven = NOT_GIVEN,
        instructions: str | NotGiven = NOT_GIVEN,
        voice_settings: VoiceSettings | NotGiven = NOT_GIVEN,
        sample_rate: int | NotGiven = NOT_GIVEN,
        format: str | NotGiven = NOT_GIVEN,
        poll_interval: float = 2.0,
        timeout: float = 300.0,
        **extra_body: object,
    ) -> Generation:
        resp = self.submit(
            model=model, input=input, voice=voice, language=language,
            speed=speed, pitch=pitch, emotion=emotion,
            instructions=instructions, voice_settings=voice_settings,
            sample_rate=sample_rate, format=format,
            **extra_body,
        )
        return self._client.generations.wait(  # type: ignore[union-attr]
            resp.request_id,
            poll_interval=poll_interval,
            timeout=timeout,
        )


class AsyncSpeech(AsyncAPIResource):
    async def submit(
        self,
        *,
        model: str,
        input: str,
        voice: str,
        language: str | NotGiven = NOT_GIVEN,
        speed: float | NotGiven = NOT_GIVEN,
        pitch: int | NotGiven = NOT_GIVEN,
        emotion: str | NotGiven = NOT_GIVEN,
        instructions: str | NotGiven = NOT_GIVEN,
        voice_settings: VoiceSettings | NotGiven = NOT_GIVEN,
        sample_rate: int | NotGiven = NOT_GIVEN,
        format: str | NotGiven = NOT_GIVEN,
        **extra_body: object,
    ) -> CreateResponse:
        body = strip_not_given({
            "model": model,
            "input": input,
            "voice": voice,
            "language": language,
            "speed": speed,
            "pitch": pitch,
            "emotion": emotion,
            "instructions": instructions,
            "voice_settings": dict(voice_settings) if is_given(voice_settings) else voice_settings,
            "sample_rate": sample_rate,
            "format": format,
        })
        for k, v in extra_body.items():
            if is_given(v):
                body[k] = v
        return await self._post("/generatespeech", cast_to=CreateResponse, body=body)

    async def generate(
        self,
        *,
        model: str,
        input: str,
        voice: str,
        language: str | NotGiven = NOT_GIVEN,
        speed: float | NotGiven = NOT_GIVEN,
        pitch: int | NotGiven = NOT_GIVEN,
        emotion: str | NotGiven = NOT_GIVEN,
        instructions: str | NotGiven = NOT_GIVEN,
        voice_settings: VoiceSettings | NotGiven = NOT_GIVEN,
        sample_rate: int | NotGiven = NOT_GIVEN,
        format: str | NotGiven = NOT_GIVEN,
        poll_interval: float = 2.0,
        timeout: float = 300.0,
        **extra_body: object,
    ) -> Generation:
        resp = await self.submit(
            model=model, input=input, voice=voice, language=language,
            speed=speed, pitch=pitch, emotion=emotion,
            instructions=instructions, voice_settings=voice_settings,
            sample_rate=sample_rate, format=format,
            **extra_body,
        )
        return await self._client.generations.wait(  # type: ignore[union-attr]
            resp.request_id,
            poll_interval=poll_interval,
            timeout=timeout,
        )
