# -*- coding: utf-8 -*-
"""
API de alto nivel - Grabador de audio.

Permite grabar audio desde dispositivos de entrada del sistema.
"""

import ctypes
from pathlib import Path
from typing import Optional

from ..dlls.bass import bass
from ..constantes.bass import BASS_RECORD_PAUSE, BASS_ACTIVE_PLAYING, BASS_ACTIVE_PAUSED, BASS_ACTIVE_STOPPED
from ..excepciones import ErrorBassNativo
from ..estructuras.bass import BASS_DEVICEINFO, BASS_RECORDINFO
from ..callbacks.bass import RECORDPROC, mantener_callback


class Grabador:
	"""
	Grabador de audio de alto nivel.

	Permite grabar desde dispositivos de entrada y guardar a archivo.

	Ejemplo:
		from basskit.alto_nivel.grabador import Grabador
		grabador = Grabador()
		grabador.inicializar()
		grabador.iniciar_grabacion()
		# ... grabar ...
		datos = grabador.detener_grabacion()
		grabador.liberar()
	"""

	def __init__(self) -> None:
		self._handle: int = 0
		self._dispositivo: int = -1
		self._inicializado: bool = False
		self._datos_grabados: bytearray = bytearray()
		self._callback_ref = None

	def listar_dispositivos(self) -> list[dict[str, str | int]]:
		"""Lista los dispositivos de grabacion disponibles."""
		dispositivos = []
		info = BASS_DEVICEINFO()
		i = 0
		while bass.BASS_RecordGetDeviceInfo(i, ctypes.byref(info)):
			nombre = info.name.decode("utf-8", errors="replace") if info.name else ""
			dispositivos.append({"indice": i, "nombre": nombre, "flags": info.flags})
			i += 1
		return dispositivos

	def inicializar(self, dispositivo: int = -1) -> None:
		"""
		Inicializa el dispositivo de grabacion.

		Parametros:
			dispositivo: -1 para dispositivo por defecto.
		"""
		self._dispositivo = dispositivo
		resultado = bass.BASS_RecordInit(dispositivo)
		if resultado == 0:
			codigo = bass.BASS_ErrorGetCode()
			raise ErrorBassNativo(codigo, "BASS_RecordInit")
		self._inicializado = True

	def iniciar_grabacion(
		self,
		frecuencia: int = 44100,
		canales: int = 2,
		flags: int = 0,
	) -> None:
		"""
		Inicia la grabacion de audio.

		Parametros:
			frecuencia: Frecuencia de muestreo.
			canales: Numero de canales (1=mono, 2=estereo).
			flags: Flags adicionales.
		"""
		if not self._inicializado:
			self.inicializar()

		self._datos_grabados.clear()

		@RECORDPROC
		def _callback(handle, buffer, length, user):
			if buffer and length > 0:
				datos = ctypes.string_at(buffer, length)
				self._datos_grabados.extend(datos)
			return 1  # Continuar grabando

		self._callback_ref = _callback
		mantener_callback(_callback)

		handle = bass.BASS_RecordStart(frecuencia, canales, flags, _callback, None)
		if handle == 0:
			codigo = bass.BASS_ErrorGetCode()
			raise ErrorBassNativo(codigo, "BASS_RecordStart")
		self._handle = handle

	def detener_grabacion(self) -> bytes:
		"""
		Detiene la grabacion y retorna los datos PCM grabados.

		Retorna:
			bytes con los datos de audio PCM capturados.
		"""
		if self._handle != 0:
			bass.BASS_ChannelStop(self._handle)
			self._handle = 0
		return bytes(self._datos_grabados)

	@property
	def grabando(self) -> bool:
		"""Indica si se esta grabando actualmente."""
		if self._handle == 0:
			return False
		return bass.BASS_ChannelIsActive(self._handle) == BASS_ACTIVE_PLAYING

	def liberar(self) -> None:
		"""Libera los recursos del dispositivo de grabacion."""
		if self._handle != 0:
			bass.BASS_ChannelStop(self._handle)
			self._handle = 0
		if self._inicializado:
			bass.BASS_RecordFree()
			self._inicializado = False

	def __del__(self) -> None:
		self.liberar()

	def __repr__(self) -> str:
		estado = "grabando" if self.grabando else "detenido"
		return f"<Grabador dispositivo={self._dispositivo} estado='{estado}'>"
