# -*- coding: utf-8 -*-
"""
API de alto nivel - Codificador/conversor de audio.

Permite convertir entre formatos usando BASSenc y sub-encoders.
"""

import ctypes
from pathlib import Path
from ..dlls.bass import bass
from ..constantes.bass import BASS_STREAM_DECODE, BASS_UNICODE, BASS_SAMPLE_FLOAT


class Codificador:
	"""
	Conversor de formatos de audio de alto nivel.

	Ejemplo:
		cod = Codificador()
		cod.convertir("entrada.wav", "salida.mp3", opciones="--preset standard")
		cod.convertir("entrada.wav", "salida.flac", opciones="-5")
		cod.convertir("entrada.wav", "salida.ogg", opciones="-q 6")
	"""

	EXTENSIONES = {
		".mp3": "mp3", ".flac": "flac", ".ogg": "ogg", ".opus": "opus",
	}

	def convertir(self, entrada: str, salida: str, opciones: str = "") -> bool:
		"""Convierte un archivo de audio a otro formato."""
		entrada = Path(entrada)
		salida = Path(salida)
		if not entrada.exists():
			raise FileNotFoundError(f"Archivo no encontrado: {entrada}")

		formato = self.EXTENSIONES.get(salida.suffix.lower())
		if not formato:
			raise ValueError(f"Formato no soportado: {salida.suffix}. Use: {list(self.EXTENSIONES.keys())}")

		ruta_b = str(entrada).encode("utf-16-le") + b"\x00\x00"
		decode = bass.BASS_StreamCreateFile(0, ruta_b, 0, 0, BASS_STREAM_DECODE | BASS_UNICODE | BASS_SAMPLE_FLOAT)
		if decode == 0:
			raise RuntimeError(f"No se pudo abrir: {entrada} (error {bass.BASS_ErrorGetCode()})")

		try:
			encoder = self._iniciar_encoder(formato, decode, str(salida), opciones)
			if encoder == 0:
				raise RuntimeError(f"Error al iniciar encoder {formato}: {bass.BASS_ErrorGetCode()}")
			buf = (ctypes.c_byte * 65536)()
			while True:
				leidos = bass.BASS_ChannelGetData(decode, ctypes.byref(buf), len(buf))
				if leidos == 0xFFFFFFFF or leidos == 0:
					break
			from ..dlls.bassenc import bassenc
			bassenc.BASS_Encode_Stop(encoder)
			return True
		finally:
			bass.BASS_StreamFree(decode)

	def _iniciar_encoder(self, formato, canal, ruta_salida, opciones):
		ruta_b = ruta_salida.encode("utf-8") if isinstance(ruta_salida, str) else ruta_salida
		opts_b = opciones.encode("utf-8") if isinstance(opciones, str) else opciones
		if formato == "mp3":
			from ..dlls.addons import bassenc_mp3
			return bassenc_mp3.BASS_Encode_MP3_StartFile(canal, opts_b or None, 0, ruta_b)
		elif formato == "flac":
			from ..dlls.addons import bassenc_flac
			return bassenc_flac.BASS_Encode_FLAC_StartFile(canal, opts_b or None, 0, ruta_b)
		elif formato == "ogg":
			from ..dlls.addons import bassenc_ogg
			return bassenc_ogg.BASS_Encode_OGG_StartFile(canal, opts_b or None, 0, ruta_b)
		elif formato == "opus":
			from ..dlls.addons import bassenc_opus
			return bassenc_opus.BASS_Encode_OPUS_StartFile(canal, opts_b or None, 0, ruta_b)
		return 0
