from __future__ import annotations

from typing import TYPE_CHECKING

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

if TYPE_CHECKING:
    from .files import AsyncFiles, Files


class Music(SyncAPIResource):
    @property
    def _files(self) -> Files:
        return self._client.files  # type: ignore[return-value]

    def _build_body(self, **kwargs: object) -> tuple[dict, list[str]]:
        temp: list[str] = []
        reference_audio = kwargs.pop("reference_audio")
        body: dict = strip_not_given(kwargs)  # type: ignore[arg-type]
        if is_given(reference_audio):
            body["reference_audio"] = self._files.resolve(reference_audio, _temp=temp)  # type: ignore[arg-type]
        return body, temp

    def submit(
        self,
        *,
        model: str,
        prompt: str,
        lyrics: str | NotGiven = NOT_GIVEN,
        title: str | NotGiven = NOT_GIVEN,
        style: str | NotGiven = NOT_GIVEN,
        duration: int | NotGiven = NOT_GIVEN,
        instrumental: bool | NotGiven = NOT_GIVEN,
        reference_audio: FileInput | NotGiven = NOT_GIVEN,
        continue_at: float | NotGiven = NOT_GIVEN,
        format: str | NotGiven = NOT_GIVEN,
        quality: str | NotGiven = NOT_GIVEN,
    ) -> CreateResponse:
        body, _ = self._build_body(
            model=model, prompt=prompt, lyrics=lyrics, title=title,
            style=style, duration=duration, instrumental=instrumental,
            reference_audio=reference_audio, continue_at=continue_at,
            format=format, quality=quality,
        )
        return self._post("/generatemusic", cast_to=CreateResponse, body=body)

    def generate(
        self,
        *,
        model: str,
        prompt: str,
        lyrics: str | NotGiven = NOT_GIVEN,
        title: str | NotGiven = NOT_GIVEN,
        style: str | NotGiven = NOT_GIVEN,
        duration: int | NotGiven = NOT_GIVEN,
        instrumental: bool | NotGiven = NOT_GIVEN,
        reference_audio: FileInput | NotGiven = NOT_GIVEN,
        continue_at: float | NotGiven = NOT_GIVEN,
        format: str | NotGiven = NOT_GIVEN,
        quality: str | NotGiven = NOT_GIVEN,
        poll_interval: float = 5.0,
        timeout: float = 600.0,
    ) -> Generation:
        body, temp_ids = self._build_body(
            model=model, prompt=prompt, lyrics=lyrics, title=title,
            style=style, duration=duration, instrumental=instrumental,
            reference_audio=reference_audio, continue_at=continue_at,
            format=format, quality=quality,
        )
        try:
            resp = self._post("/generatemusic", cast_to=CreateResponse, body=body)
            return self._client.generations.wait(  # type: ignore[union-attr]
                resp.request_id,
                poll_interval=poll_interval,
                timeout=timeout,
            )
        finally:
            if temp_ids:
                self._files.cleanup(temp_ids)


class AsyncMusic(AsyncAPIResource):
    @property
    def _files(self) -> AsyncFiles:
        return self._client.files  # type: ignore[return-value]

    async def _build_body(self, **kwargs: object) -> tuple[dict, list[str]]:
        temp: list[str] = []
        reference_audio = kwargs.pop("reference_audio")
        body: dict = strip_not_given(kwargs)  # type: ignore[arg-type]
        if is_given(reference_audio):
            body["reference_audio"] = await self._files.resolve(reference_audio, _temp=temp)  # type: ignore[arg-type]
        return body, temp

    async def submit(
        self,
        *,
        model: str,
        prompt: str,
        lyrics: str | NotGiven = NOT_GIVEN,
        title: str | NotGiven = NOT_GIVEN,
        style: str | NotGiven = NOT_GIVEN,
        duration: int | NotGiven = NOT_GIVEN,
        instrumental: bool | NotGiven = NOT_GIVEN,
        reference_audio: FileInput | NotGiven = NOT_GIVEN,
        continue_at: float | NotGiven = NOT_GIVEN,
        format: str | NotGiven = NOT_GIVEN,
        quality: str | NotGiven = NOT_GIVEN,
    ) -> CreateResponse:
        body, _ = await self._build_body(
            model=model, prompt=prompt, lyrics=lyrics, title=title,
            style=style, duration=duration, instrumental=instrumental,
            reference_audio=reference_audio, continue_at=continue_at,
            format=format, quality=quality,
        )
        return await self._post("/generatemusic", cast_to=CreateResponse, body=body)

    async def generate(
        self,
        *,
        model: str,
        prompt: str,
        lyrics: str | NotGiven = NOT_GIVEN,
        title: str | NotGiven = NOT_GIVEN,
        style: str | NotGiven = NOT_GIVEN,
        duration: int | NotGiven = NOT_GIVEN,
        instrumental: bool | NotGiven = NOT_GIVEN,
        reference_audio: FileInput | NotGiven = NOT_GIVEN,
        continue_at: float | NotGiven = NOT_GIVEN,
        format: str | NotGiven = NOT_GIVEN,
        quality: str | NotGiven = NOT_GIVEN,
        poll_interval: float = 5.0,
        timeout: float = 600.0,
    ) -> Generation:
        body, temp_ids = await self._build_body(
            model=model, prompt=prompt, lyrics=lyrics, title=title,
            style=style, duration=duration, instrumental=instrumental,
            reference_audio=reference_audio, continue_at=continue_at,
            format=format, quality=quality,
        )
        try:
            resp = await self._post("/generatemusic", cast_to=CreateResponse, body=body)
            return await self._client.generations.wait(  # type: ignore[union-attr]
                resp.request_id,
                poll_interval=poll_interval,
                timeout=timeout,
            )
        finally:
            if temp_ids:
                await self._files.cleanup(temp_ids)
