# -*- coding: utf-8 -*-
"""
Herramientas de diagnóstico para basskit.

Permite verificar la instalación, las DLL disponibles,
la versión de BASS y el estado general del sistema.
"""

import platform
import struct
import sys
from pathlib import Path
from typing import Any

from ..rutas import obtener_directorio_paquete, listar_dlls_disponibles
from ..tipos import version_a_texto


def diagnostico() -> dict[str, Any]:
	"""
	Ejecuta un diagnóstico completo del sistema y la instalación.

	Retorna:
		Diccionario con información detallada del diagnóstico.
	"""
	info: dict[str, Any] = {
		"python_version": f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}",
		"plataforma": platform.system(),
		"arquitectura": f"{struct.calcsize('P') * 8} bits",
		"arquitectura_os": platform.machine(),
		"ruta_paquete": str(obtener_directorio_paquete()),
		"dlls_encontradas": [],
		"dlls_cargables": [],
		"dlls_con_error": [],
		"version_bass": None,
		"estado": "pendiente",
		"mensajes": [],
	}

	# Verificar plataforma
	if platform.system() != "Windows":
		info["estado"] = "error"
		info["mensajes"].append(
			f"Plataforma no soportada: {platform.system()}. basskit solo funciona en Windows."
		)
		return info

	bits = struct.calcsize("P") * 8
	if bits != 64:
		info["estado"] = "error"
		info["mensajes"].append(
			f"Arquitectura no soportada: Python {bits} bits. basskit requiere Python 64 bits."
		)
		return info

	if sys.version_info < (3, 13):
		info["mensajes"].append(
			f"Advertencia: Python {info['python_version']}. Se recomienda 3.13+."
		)

	# Buscar DLLs
	dlls = listar_dlls_disponibles()
	info["dlls_encontradas"] = [d.name for d in dlls]

	if not dlls:
		info["estado"] = "error"
		info["mensajes"].append(
			"No se encontraron DLL en el directorio del paquete."
		)
		return info

	# Verificar DLL principal
	bass_dll = None
	for dll in dlls:
		if dll.name.lower() == "bass.dll":
			bass_dll = dll
			break

	if bass_dll is None:
		info["estado"] = "error"
		info["mensajes"].append(
			"No se encontró bass.dll. Es obligatoria."
		)
		return info

	# Intentar cargar DLLs
	import ctypes
	import os

	try:
		ruta_dlls = bass_dll.parent
		if hasattr(os, "add_dll_directory"):
			os.add_dll_directory(str(ruta_dlls))

		# Cargar bass.dll
		try:
			bass_cargada = ctypes.WinDLL(str(bass_dll))
			info["dlls_cargables"].append("bass.dll")

			# Obtener versión
			bass_cargada.BASS_GetVersion.restype = ctypes.c_ulong
			bass_cargada.BASS_GetVersion.argtypes = []
			version_raw = bass_cargada.BASS_GetVersion()
			info["version_bass"] = version_a_texto(version_raw)
			info["mensajes"].append(
				f"bass.dll cargada correctamente. Versión: {info['version_bass']}"
			)
		except OSError as e:
			info["dlls_con_error"].append({"dll": "bass.dll", "error": str(e)})
			info["estado"] = "error"
			info["mensajes"].append(f"Error al cargar bass.dll: {e}")
			return info

		# Probar add-ons
		for dll in dlls:
			if dll.name.lower() == "bass.dll":
				continue
			try:
				ctypes.WinDLL(str(dll))
				info["dlls_cargables"].append(dll.name)
			except OSError as e:
				info["dlls_con_error"].append({"dll": dll.name, "error": str(e)})

	except Exception as e:
		info["estado"] = "error"
		info["mensajes"].append(f"Error inesperado durante el diagnóstico: {e}")
		return info

	# Evaluar estado
	if info["dlls_con_error"]:
		info["estado"] = "parcial"
		info["mensajes"].append(
			f"{len(info['dlls_con_error'])} DLL(s) con error de carga."
		)
	else:
		info["estado"] = "correcto"
		info["mensajes"].append(
			f"Todo correcto. {len(info['dlls_cargables'])} DLL(s) cargables."
		)

	return info


def imprimir_diagnostico() -> None:
	"""Imprime el diagnóstico en formato legible por consola."""
	info = diagnostico()

	print("=" * 60)
	print("  DIAGNÓSTICO DE BASSKIT")
	print("=" * 60)
	print(f"  Python:        {info['python_version']}")
	print(f"  Plataforma:    {info['plataforma']}")
	print(f"  Arquitectura:  {info['arquitectura']}")
	print(f"  Ruta paquete:  {info['ruta_paquete']}")
	print(f"  Versión BASS:  {info['version_bass'] or 'No disponible'}")
	print(f"  Estado:        {info['estado'].upper()}")
	print("-" * 60)
	print(f"  DLL encontradas:  {len(info['dlls_encontradas'])}")
	print(f"  DLL cargables:    {len(info['dlls_cargables'])}")
	print(f"  DLL con error:    {len(info['dlls_con_error'])}")

	if info["dlls_con_error"]:
		print("\n  DLL con errores:")
		for err in info["dlls_con_error"]:
			print(f"    - {err['dll']}: {err['error']}")

	if info["mensajes"]:
		print("\n  Mensajes:")
		for msg in info["mensajes"]:
			print(f"    • {msg}")

	print("=" * 60)


if __name__ == "__main__":
	imprimir_diagnostico()
