# -*- coding: utf-8 -*-
"""
Tipos callback de BASS (bass.dll).

Define los tipos de función callback utilizados por BASS.
IMPORTANTE: Las instancias de callbacks deben mantenerse como
referencias vivas en Python para evitar que el recolector de
basura las libere mientras BASS las está usando.
"""

import ctypes
from ..tipos import (
	HSTREAM, HRECORD, HSYNC, HDSP, HFX, QWORD, DWORD, BOOL,
)


# ─── Tipo base de callback ───────────────────────────────────────────
# BASS usa __stdcall en Windows
BASSCALLBACK = ctypes.WINFUNCTYPE


# ─── STREAMPROC ──────────────────────────────────────────────────────
# typedef DWORD (CALLBACK STREAMPROC)(HSTREAM handle, void *buffer, DWORD length, void *user);
STREAMPROC = BASSCALLBACK(
	ctypes.c_ulong,			# retorno: bytes escritos
	ctypes.c_ulong,			# handle: HSTREAM
	ctypes.c_void_p,			# buffer
	ctypes.c_ulong,			# length
	ctypes.c_void_p,			# user
)

# ─── DOWNLOADPROC ────────────────────────────────────────────────────
# typedef void (CALLBACK DOWNLOADPROC)(const void *buffer, DWORD length, void *user);
DOWNLOADPROC = BASSCALLBACK(
	None,						# retorno: void
	ctypes.c_void_p,			# buffer
	ctypes.c_ulong,			# length
	ctypes.c_void_p,			# user
)

# ─── SYNCPROC ────────────────────────────────────────────────────────
# typedef void (CALLBACK SYNCPROC)(HSYNC handle, DWORD channel, DWORD data, void *user);
SYNCPROC = BASSCALLBACK(
	None,						# retorno: void
	ctypes.c_ulong,			# handle: HSYNC
	ctypes.c_ulong,			# channel
	ctypes.c_ulong,			# data
	ctypes.c_void_p,			# user
)

# ─── DSPPROC ─────────────────────────────────────────────────────────
# typedef void (CALLBACK DSPPROC)(HDSP handle, DWORD channel, void *buffer, DWORD length, void *user);
DSPPROC = BASSCALLBACK(
	None,						# retorno: void
	ctypes.c_ulong,			# handle: HDSP
	ctypes.c_ulong,			# channel
	ctypes.c_void_p,			# buffer
	ctypes.c_ulong,			# length
	ctypes.c_void_p,			# user
)

# ─── RECORDPROC ──────────────────────────────────────────────────────
# typedef BOOL (CALLBACK RECORDPROC)(HRECORD handle, const void *buffer, DWORD length, void *user);
RECORDPROC = BASSCALLBACK(
	ctypes.c_int,				# retorno: BOOL (TRUE=continuar, FALSE=detener)
	ctypes.c_ulong,			# handle: HRECORD
	ctypes.c_void_p,			# buffer
	ctypes.c_ulong,			# length
	ctypes.c_void_p,			# user
)

# ─── FILECLOSEPROC ───────────────────────────────────────────────────
# typedef void (CALLBACK FILECLOSEPROC)(void *user);
FILECLOSEPROC = BASSCALLBACK(
	None,
	ctypes.c_void_p,
)

# ─── FILELENPROC ─────────────────────────────────────────────────────
# typedef QWORD (CALLBACK FILELENPROC)(void *user);
FILELENPROC = BASSCALLBACK(
	ctypes.c_int64,				# retorno: QWORD
	ctypes.c_void_p,
)

# ─── FILEREADPROC ────────────────────────────────────────────────────
# typedef DWORD (CALLBACK FILEREADPROC)(void *buffer, DWORD length, void *user);
FILEREADPROC = BASSCALLBACK(
	ctypes.c_ulong,
	ctypes.c_void_p,
	ctypes.c_ulong,
	ctypes.c_void_p,
)

# ─── FILESEEKPROC ────────────────────────────────────────────────────
# typedef BOOL (CALLBACK FILESEEKPROC)(QWORD offset, void *user);
FILESEEKPROC = BASSCALLBACK(
	ctypes.c_int,				# retorno: BOOL
	ctypes.c_int64,				# offset: QWORD
	ctypes.c_void_p,
)

# ─── DEVICENOTIFYPROC ────────────────────────────────────────────────
# typedef void (CALLBACK DEVICENOTIFYPROC)(DWORD action, void *user);
DEVICENOTIFYPROC = BASSCALLBACK(
	None,
	ctypes.c_ulong,
	ctypes.c_void_p,
)


# ─── Estructura BASS_FILEPROCS ───────────────────────────────────────
class BASS_FILEPROCS(ctypes.Structure):
	"""Estructura con punteros a funciones de archivo personalizadas."""
	_fields_ = [
		("close", FILECLOSEPROC),
		("length", FILELENPROC),
		("read", FILEREADPROC),
		("seek", FILESEEKPROC),
	]


# ─── Estructura BASS_FILEOPENPROCS ───────────────────────────────────
# FILEOPENPROC necesita retornar un pointer
FILEOPENPROC = BASSCALLBACK(
	ctypes.c_void_p,			# retorno: user data pointer
	ctypes.c_char_p,			# file: nombre del archivo
	ctypes.c_void_p,			# user
)

class BASS_FILEOPENPROCS(ctypes.Structure):
	"""Estructura para interceptar apertura de archivos."""
	_fields_ = [
		("open", FILEOPENPROC),
		("procs", ctypes.POINTER(BASS_FILEPROCS)),
	]


# ─── Gestor de referencias a callbacks ───────────────────────────────
# IMPORTANTE: Los callbacks deben mantenerse vivos mientras BASS los use.
# Este gestor almacena referencias para evitar la recolección de basura.

_referencias_callbacks: list = []


def mantener_callback(callback) -> None:
	"""
	Mantiene una referencia al callback para evitar que sea recolectado.

	Parámetros:
		callback: Instancia de callback ctypes.
	"""
	_referencias_callbacks.append(callback)


def limpiar_callbacks() -> None:
	"""Limpia todas las referencias a callbacks almacenadas."""
	_referencias_callbacks.clear()
